Compare commits

..

7 Commits

60 changed files with 262 additions and 287 deletions

View File

@@ -9,18 +9,22 @@
], ],
"require": { "require": {
"php": "^7.4", "php": "^7.4",
"ext-json": "*",
"ext-openssl": "*",
"ext-redis": "*",
"champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290", "champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290",
"champs-libres/wopi-bundle": "dev-master#6dd8e0a14e00131eb4b889ecc30270ee4a0e5224", "champs-libres/wopi-bundle": "dev-master@dev",
"champs-libres/wopi-lib": "dev-master#8615f4a45a39fc2b6a98765ea835fcfd39618787", "champs-libres/wopi-lib": "dev-master@dev",
"doctrine/doctrine-bundle": "^2.1", "doctrine/doctrine-bundle": "^2.1",
"doctrine/doctrine-migrations-bundle": "^3.0", "doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7", "doctrine/orm": "^2.13.0",
"erusev/parsedown": "^1.7", "erusev/parsedown": "^1.7",
"graylog2/gelf-php": "^1.5", "graylog2/gelf-php": "^1.5",
"knplabs/knp-menu-bundle": "^3.0", "knplabs/knp-menu-bundle": "^3.0",
"knplabs/knp-time-bundle": "^1.12", "knplabs/knp-time-bundle": "^1.12",
"knpuniversity/oauth2-client-bundle": "^2.10", "knpuniversity/oauth2-client-bundle": "^2.10",
"league/csv": "^9.7.1", "league/csv": "^9.7.1",
"lexik/jwt-authentication-bundle": "^2.16",
"nyholm/psr7": "^1.4", "nyholm/psr7": "^1.4",
"ocramius/package-versions": "^1.10 || ^2", "ocramius/package-versions": "^1.10 || ^2",
"odolbeau/phone-number-bundle": "^3.6", "odolbeau/phone-number-bundle": "^3.6",
@@ -29,12 +33,12 @@
"ramsey/uuid-doctrine": "^1.7", "ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5", "sensio/framework-extra-bundle": "^5.5",
"spomky-labs/base64url": "^2.0", "spomky-labs/base64url": "^2.0",
"symfony/asset": "^4.4",
"symfony/browser-kit": "^4.4", "symfony/browser-kit": "^4.4",
"symfony/css-selector": "^4.4", "symfony/css-selector": "^4.4",
"symfony/expression-language": "^4.4", "symfony/expression-language": "^4.4",
"symfony/form": "^4.4", "symfony/form": "^4.4",
"symfony/framework-bundle": "^4.4", "symfony/framework-bundle": "^4.4",
"symfony/http-client": "^4.4 || ^5",
"symfony/http-foundation": "^4.4", "symfony/http-foundation": "^4.4",
"symfony/intl": "^4.4", "symfony/intl": "^4.4",
"symfony/mailer": "^5.4", "symfony/mailer": "^5.4",
@@ -72,8 +76,7 @@
"symfony/maker-bundle": "^1.20", "symfony/maker-bundle": "^1.20",
"symfony/phpunit-bridge": "^4.4", "symfony/phpunit-bridge": "^4.4",
"symfony/stopwatch": "^4.4", "symfony/stopwatch": "^4.4",
"symfony/var-dumper": "^4.4", "symfony/var-dumper": "^4.4"
"symfony/web-profiler-bundle": "^4.4"
}, },
"conflict": { "conflict": {
"symfony/symfony": "*" "symfony/symfony": "*"

View File

@@ -60,7 +60,7 @@ class ByCreatorAggregator implements AggregatorInterface
return 'Created by'; return 'Created by';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ class BySocialActionAggregator implements AggregatorInterface
return 'Social action'; return 'Social action';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ class BySocialIssueAggregator implements AggregatorInterface
return 'Social issues'; return 'Social issues';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ class ByThirdpartyAggregator implements AggregatorInterface
return 'Accepted thirdparty'; return 'Accepted thirdparty';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ class CreatorScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,13 +65,11 @@ class LocationTypeAggregator implements AggregatorInterface
return 'Accepted locationtype'; return 'Accepted locationtype';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }
if (null === $lt = $this->locationTypeRepository->find($value)) { $lt = $this->locationTypeRepository->find($value);
return '';
}
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(
$lt->getTitle() $lt->getTitle()

View File

@@ -71,7 +71,7 @@ class ActivityTypeAggregator implements AggregatorInterface
return 'Activity type'; return 'Activity type';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -66,7 +66,7 @@ class ActivityUserAggregator implements AggregatorInterface
return 'Activity user'; return 'Activity user';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -64,7 +64,7 @@ class ActivityUsersAggregator implements AggregatorInterface
return 'Activity users'; return 'Activity users';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -63,7 +63,7 @@ class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorI
return 'Users \'s job'; return 'Users \'s job';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -63,7 +63,7 @@ class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\Aggregato
return 'Users \'s scope'; return 'Users \'s scope';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -134,10 +134,6 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason'; return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason';
} }
if (null === $value || '' === $value) {
return '';
}
switch ($data['level']) { switch ($data['level']) {
case 'reasons': case 'reasons':
$r = $this->activityReasonRepository->find($value); $r = $this->activityReasonRepository->find($value);

View File

@@ -57,7 +57,6 @@ class SentReceivedAggregator implements AggregatorInterface
switch ($value) { switch ($value) {
case null: case null:
case '':
return ''; return '';
case 'sent': case 'sent':

View File

@@ -17,9 +17,11 @@ use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ActivityTypeFilter implements FilterInterface class ActivityTypeFilter implements FilterInterface
{ {
@@ -42,13 +44,14 @@ class ActivityTypeFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->andWhere( if (!in_array('activity', $qb->getAllAliases(), true)) {
$qb->expr()->exists( $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp');
'SELECT 1 FROM ' . Activity::class . ' act_type_filter_activity }
WHERE act_type_filter_activity.activityType IN (:act_type_filter_activity_types) AND act_type_filter_activity.accompanyingPeriod = acp'
) $clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
);
$qb->setParameter('act_type_filter_activity_types', $data['accepted_activitytypes']); $qb->andWhere($clause);
$qb->setParameter('selected_activity_types', $data['types']);
} }
public function applyOn() public function applyOn()

View File

@@ -66,10 +66,6 @@ final class AgentAggregator implements AggregatorInterface
return 'Agent'; return 'Agent';
} }
if (null === $value || '' === $value) {
return '';
}
$r = $this->userRepository->find($value); $r = $this->userRepository->find($value);
return $this->userRender->renderString($r, []); return $this->userRender->renderString($r, []);

View File

@@ -67,10 +67,6 @@ class CancelReasonAggregator implements AggregatorInterface
return 'Cancel reason'; return 'Cancel reason';
} }
if (null === $value || '' === $value) {
return '';
}
$j = $this->cancelReasonRepository->find($value); $j = $this->cancelReasonRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -66,10 +66,6 @@ final class JobAggregator implements AggregatorInterface
return 'Job'; return 'Job';
} }
if (null === $value || '' === $value) {
return '';
}
$j = $this->jobRepository->find($value); $j = $this->jobRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -60,10 +60,6 @@ final class LocationAggregator implements AggregatorInterface
return 'Location'; return 'Location';
} }
if (null === $value || '' === $value) {
return '';
}
$l = $this->locationRepository->find($value); $l = $this->locationRepository->find($value);
return $l->getName(); return $l->getName();

View File

@@ -66,13 +66,7 @@ final class LocationTypeAggregator implements AggregatorInterface
return 'Location type'; return 'Location type';
} }
if (null === $value || '' === $value) { $j = $this->locationTypeRepository->find($value);
return '';
}
if (null === $j = $this->locationTypeRepository->find($value)) {
return '';
}
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(
$j->getTitle() $j->getTitle()

View File

@@ -66,10 +66,6 @@ final class ScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value || '' === $value) {
return '';
}
$s = $this->scopeRepository->find($value); $s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -60,7 +60,7 @@ final class StoredObjectManager implements StoredObjectManagerInterface
$this $this
->tempUrlGenerator ->tempUrlGenerator
->generate( ->generate(
Request::METHOD_PUT, Request::METHOD_HEAD,
$document->getFilename() $document->getFilename()
) )
->url ->url

View File

@@ -15,7 +15,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use RuntimeException; use RuntimeException;
use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -31,7 +31,7 @@ use function in_array;
* "user": User::class * "user": User::class
* }) * })
*/ */
class User implements AdvancedUserInterface class User implements UserInterface
{ {
/** /**
* @ORM\Id * @ORM\Id
@@ -58,8 +58,6 @@ class User implements AdvancedUserInterface
private ?Location $currentLocation = null; private ?Location $currentLocation = null;
/** /**
* @var string
*
* @ORM\Column(type="string", length=150, nullable=true) * @ORM\Column(type="string", length=150, nullable=true)
*/ */
private ?string $email = null; private ?string $email = null;
@@ -216,7 +214,7 @@ class User implements AdvancedUserInterface
} }
/** /**
* @return GroupCenter * @return Collection<GroupCenter>
*/ */
public function getGroupCenters() public function getGroupCenters()
{ {
@@ -225,10 +223,8 @@ class User implements AdvancedUserInterface
/** /**
* Get id. * Get id.
*
* @return int
*/ */
public function getId() public function getId(): int
{ {
return $this->id; return $this->id;
} }
@@ -487,7 +483,7 @@ class User implements AdvancedUserInterface
* *
* @param string $name * @param string $name
* *
* @return Agent * @return User
*/ */
public function setUsername($name) public function setUsername($name)
{ {

View File

@@ -11,7 +11,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Security\Authorization; namespace Chill\MainBundle\Security\Authorization;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;

View File

@@ -11,9 +11,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Security\Authorization; namespace Chill\MainBundle\Security\Authorization;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Scope;
interface AuthorizationHelperForCurrentUserInterface interface AuthorizationHelperForCurrentUserInterface
{ {
/** /**

View File

@@ -65,7 +65,7 @@ class AdministrativeLocationAggregator implements AggregatorInterface
return 'Administrative location'; return 'Administrative location';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -60,7 +60,7 @@ class ClosingMotiveAggregator implements AggregatorInterface
return 'Closing motive'; return 'Closing motive';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ class CreatorJobAggregator implements AggregatorInterface
return 'export.aggregator.course.by_creator_job.Creator\'s job'; return 'export.aggregator.course.by_creator_job.Creator\'s job';
} }
if (null === $value || '' === $value || null === $j = $this->jobRepository->find($value)) { if (null === $value || null === $j = $this->jobRepository->find($value)) {
return ''; return '';
} }

View File

@@ -69,7 +69,7 @@ final class EvaluationAggregator implements AggregatorInterface
return 'Evaluation'; return 'Evaluation';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -143,7 +143,7 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface
return 'acp_geog_agg_unitname'; return 'acp_geog_agg_unitname';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ final class JobAggregator implements AggregatorInterface
return 'Job'; return 'Job';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -67,7 +67,7 @@ final class OriginAggregator implements AggregatorInterface
return 'Origin'; return 'Origin';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -94,7 +94,7 @@ final class ReferrerAggregator implements AggregatorInterface
return 'Referrer'; return 'Referrer';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -101,7 +101,7 @@ class ReferrerScopeAggregator implements AggregatorInterface
return 'export.aggregator.course.by_user_scope.Referrer\'s scope'; return 'export.aggregator.course.by_user_scope.Referrer\'s scope';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,13 +65,11 @@ final class ScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }
if (null === $s = $this->scopeRepository->find($value)) { $s = $this->scopeRepository->find($value);
return '';
}
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(
$s->getName() $s->getName()

View File

@@ -66,13 +66,11 @@ final class SocialActionAggregator implements AggregatorInterface
return 'Social action'; return 'Social action';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }
if (null === $sa = $this->actionRepository->find($value)) { $sa = $this->actionRepository->find($value);
return '';
}
return $this->actionRender->renderString($sa, []); return $this->actionRender->renderString($sa, []);
}; };

View File

@@ -66,10 +66,6 @@ final class SocialIssueAggregator implements AggregatorInterface
return 'Social issues'; return 'Social issues';
} }
if (null === $value || '' === $value) {
return '';
}
$i = $this->issueRepository->find($value); $i = $this->issueRepository->find($value);
return $this->issueRender->renderString($i, []); return $this->issueRender->renderString($i, []);

View File

@@ -98,7 +98,6 @@ final class StepAggregator implements AggregatorInterface
return 'Step'; return 'Step';
case null: case null:
case '':
return ''; return '';
default: default:

View File

@@ -60,7 +60,7 @@ class EvaluationTypeAggregator implements AggregatorInterface
return 'Evaluation type'; return 'Evaluation type';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -89,7 +89,7 @@ class CompositionAggregator implements AggregatorInterface
return 'Composition'; return 'Composition';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -105,7 +105,7 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface
return 'export.aggregator.person.by_household_composition.Household composition'; return 'export.aggregator.person.by_household_composition.Household composition';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -66,7 +66,6 @@ final class GenderAggregator implements AggregatorInterface
return $this->translator->trans('unknown'); return $this->translator->trans('unknown');
case null: case null:
case '':
return $this->translator->trans('Not given'); return $this->translator->trans('Not given');
case '_header': case '_header':

View File

@@ -101,7 +101,7 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl
return 'Household position'; return 'Household position';
} }
if (null === $value || '' === $value) { if (null === $value) {
return $this->translator->trans('without data'); return $this->translator->trans('without data');
} }

View File

@@ -63,10 +63,6 @@ final class MaritalStatusAggregator implements AggregatorInterface
return 'Marital status'; return 'Marital status';
} }
if (null === $value || '' === $value) {
return '';
}
$g = $this->maritalStatusRepository->find($value); $g = $this->maritalStatusRepository->find($value);
return $this->translatableStringHelper->localize($g->getName()); return $this->translatableStringHelper->localize($g->getName());

View File

@@ -85,7 +85,7 @@ final class ActionTypeAggregator implements AggregatorInterface
return 'Social Action Type'; return 'Social Action Type';
} }
if (null === $value || '' === $value || null === $sa = $this->socialActionRepository->find($value)) { if (null === $value || null === $sa = $this->socialActionRepository->find($value)) {
return ''; return '';
} }

View File

@@ -63,7 +63,7 @@ final class GoalAggregator implements AggregatorInterface
return 'Goal Type'; return 'Goal Type';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -72,7 +72,7 @@ class GoalResultAggregator implements AggregatorInterface
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
return function ($value) use ($key): string { return function ($value) use ($key): string {
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ final class JobAggregator implements AggregatorInterface
return 'Job'; return 'Job';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ final class ReferrerAggregator implements AggregatorInterface
return 'Referrer'; return 'Referrer';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -63,7 +63,7 @@ final class ResultAggregator implements AggregatorInterface
return 'Result Type'; return 'Result Type';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -65,7 +65,7 @@ final class ScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value || '' === $value) { if (null === $value) {
return ''; return '';
} }

View File

@@ -70,11 +70,11 @@ class GeographicalUnitStatFilter implements FilterInterface
LEFT JOIN acp_geog_filter_address.geographicalUnits acp_geog_filter_units LEFT JOIN acp_geog_filter_address.geographicalUnits acp_geog_filter_units
WHERE WHERE
(acp_geog_filter_location_history.startDate <= :acp_geog_filter_date AND ( (acp_geog_filter_location_history.startDate <= :acp_geog_filter_date AND (
acp_geog_filter_location_history.endDate IS NULL OR acp_geog_filter_location_history.endDate > :acp_geog_filter_date acp_geog_filter_location_history.endDate IS NULL OR acp_geog_filter_location_history.endDate < :acp_geog_filter_date
)) ))
AND AND
(acp_geog_filter_address_person_location.validFrom < :acp_geog_filter_date AND ( (acp_geog_filter_address_person_location.validFrom < :acp_geog_filter_date AND (
acp_geog_filter_address_person_location.validTo IS NULL OR acp_geog_filter_address_person_location.validTo > :acp_geog_filter_date acp_geog_filter_address_person_location.validTo IS NULL OR acp_geog_filter_address_person_location.validTo < :acp_geog_filter_date
)) ))
AND acp_geog_filter_units IN (:acp_geog_filter_units) AND acp_geog_filter_units IN (:acp_geog_filter_units)
AND acp_geog_filter_location_history.period = acp.id AND acp_geog_filter_location_history.period = acp.id

View File

@@ -111,10 +111,10 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return [ return [
'export.filter.by_geog_unit.Filtered by person\'s geographical unit (based on address) computed at %datecalc%, only %units%', 'exports.by_person.Filtered by person\'s geographical unit (based on address) computed at datecalc, only units',
[ [
'%datecalc%' => $this->rollingDateConverter->convert($data['date_calc'])->format('Y-m-d'), 'datecalc' => $this->rollingDateConverter->convert($data['date_calc'])->format('Y-m-d'),
'%units%' => implode( 'units' => implode(
', ', ', ',
array_map( array_map(
function (SimpleGeographicalUnitDTO $item) { function (SimpleGeographicalUnitDTO $item) {

View File

@@ -1046,8 +1046,6 @@ export:
Max date: Date d'échéance Max date: Date d'échéance
filter: filter:
by_geog_unit:
Filtered by person's geographical unit (based on address) computed at %datecalc%, only %units%: Filtré par unité géographique (sur base de l'adresse), calculé le %datecalc%, seulement %units%
person: person:
by_composition: by_composition:
Filter by household composition: Filtrer les personnes par composition du ménage Filter by household composition: Filtrer les personnes par composition du ménage

View File

@@ -15,11 +15,13 @@ use ChampsLibres\WopiLib\Contract\Service\Configuration\ConfigurationInterface;
use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface; use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface;
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\User;
use Chill\WopiBundle\Service\Controller\ResponderInterface; use Chill\WopiBundle\Service\Controller\ResponderInterface;
use Exception; use Exception;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use loophp\psr17\Psr17Interface; use loophp\psr17\Psr17Interface;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Routing\RouterInterface;
@@ -33,6 +35,8 @@ final class Editor
{ {
private DocumentManagerInterface $documentManager; private DocumentManagerInterface $documentManager;
private JWTTokenManagerInterface $JWTTokenManager;
private Psr17Interface $psr17; private Psr17Interface $psr17;
private ResponderInterface $responder; private ResponderInterface $responder;
@@ -49,12 +53,14 @@ final class Editor
ConfigurationInterface $wopiConfiguration, ConfigurationInterface $wopiConfiguration,
DiscoveryInterface $wopiDiscovery, DiscoveryInterface $wopiDiscovery,
DocumentManagerInterface $documentManager, DocumentManagerInterface $documentManager,
JWTTokenManagerInterface $JWTTokenManager,
ResponderInterface $responder, ResponderInterface $responder,
Security $security, Security $security,
Psr17Interface $psr17, Psr17Interface $psr17,
RouterInterface $router RouterInterface $router
) { ) {
$this->documentManager = $documentManager; $this->documentManager = $documentManager;
$this->JWTTokenManager = $JWTTokenManager;
$this->wopiConfiguration = $wopiConfiguration; $this->wopiConfiguration = $wopiConfiguration;
$this->wopiDiscovery = $wopiDiscovery; $this->wopiDiscovery = $wopiDiscovery;
$this->responder = $responder; $this->responder = $responder;
@@ -65,8 +71,12 @@ final class Editor
public function __invoke(string $fileId): Response public function __invoke(string $fileId): Response
{ {
if (null === $user = $this->security->getUser()->getUsername()) { if (null === $user = $this->security->getUser()) {
throw new AccessDeniedException('You must be logged in to access to this resource.'); throw new AccessDeniedHttpException('Please authenticate to access this feature');
}
if (!$user instanceof User) {
throw new AccessDeniedHttpException('Please authenticate as a user to access this feature');
} }
$configuration = $this->wopiConfiguration->jsonSerialize(); $configuration = $this->wopiConfiguration->jsonSerialize();
@@ -82,7 +92,19 @@ final class Editor
} }
$configuration['favIconUrl'] = ''; $configuration['favIconUrl'] = '';
$configuration['access_token'] = $user; $configuration['access_token'] = $this->JWTTokenManager->createFromPayload($user, [
'UserCanWrite' => true,
'UserCanAttend' => true,
'UserCanPresent' => true,
'fileId' => $fileId,
]);
// we parse the token back to get the access_token_ttl
// reminder: access_token_ttl is a javascript epoch, not a number of seconds; it is the
// time when the token will expire, not the time to live:
// https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/concepts#the-access_token_ttl-property
$jwt = $this->JWTTokenManager->parse($configuration['access_token']);
$configuration['access_token_ttl'] = $jwt['exp'] * 1000;
$configuration['server'] = $this $configuration['server'] = $this
->psr17 ->psr17

View File

@@ -12,12 +12,15 @@ declare(strict_types=1);
namespace Symfony\Component\DependencyInjection\Loader\Configurator; namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface; use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface;
use ChampsLibres\WopiBundle\Contracts\AuthorizationManagerInterface;
use ChampsLibres\WopiBundle\Contracts\UserManagerInterface;
use ChampsLibres\WopiBundle\Service\Wopi as CLWopi; use ChampsLibres\WopiBundle\Service\Wopi as CLWopi;
use ChampsLibres\WopiLib\Contract\Service\DocumentLockManagerInterface;
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
use Chill\WopiBundle\Service\Wopi\AuthorizationManager;
use Chill\WopiBundle\Service\Wopi\ChillDocumentLockManager; use Chill\WopiBundle\Service\Wopi\ChillDocumentLockManager;
use Chill\WopiBundle\Service\Wopi\ChillDocumentManager; use Chill\WopiBundle\Service\Wopi\ChillDocumentManager;
use Chill\WopiBundle\Service\Wopi\ChillWopi; use Chill\WopiBundle\Service\Wopi\ChillWopi;
use Chill\WopiBundle\Service\Wopi\UserManager;
return static function (ContainerConfigurator $container) { return static function (ContainerConfigurator $container) {
$services = $container $services = $container
@@ -44,8 +47,17 @@ return static function (ContainerConfigurator $container) {
->alias(DocumentManagerInterface::class, ChillDocumentManager::class); ->alias(DocumentManagerInterface::class, ChillDocumentManager::class);
$services $services
->set(ChillDocumentLockManager::class) ->set(ChillDocumentLockManager::class);
->decorate(DocumentLockManagerInterface::class);
$services
->set(AuthorizationManager::class);
$services->alias(AuthorizationManagerInterface::class, AuthorizationManager::class);
$services
->set(UserManager::class);
$services->alias(UserManagerInterface::class, UserManager::class);
// TODO: Move this into the async bundle (low priority) // TODO: Move this into the async bundle (low priority)
$services $services

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\WopiBundle\Service\Wopi;
use ChampsLibres\WopiLib\Contract\Entity\Document;
use Chill\MainBundle\Entity\User;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\Security\Core\Security;
class AuthorizationManager implements \ChampsLibres\WopiBundle\Contracts\AuthorizationManagerInterface
{
private Security $security;
private JWTTokenManagerInterface $tokenManager;
public function __construct(JWTTokenManagerInterface $tokenManager, Security $security)
{
$this->tokenManager = $tokenManager;
$this->security = $security;
}
public function isRestrictedWebViewOnly(string $accessToken, Document $document, RequestInterface $request): bool
{
return false;
}
public function isTokenValid(string $accessToken, Document $document, RequestInterface $request): bool
{
$metadata = $this->tokenManager->parse($accessToken);
if (false === $metadata) {
return false;
}
$user = $this->security->getUser();
if (!$user instanceof User) {
return false;
}
return $document->getWopiDocId() === $metadata['fileId'];
}
public function userCanAttend(string $accessToken, Document $document, RequestInterface $request): bool
{
return $this->isTokenValid($accessToken, $document, $request);
}
public function userCanDelete(string $accessToken, Document $document, RequestInterface $request): bool
{
return false;
}
public function userCannotWriteRelative(string $accessToken, Document $document, RequestInterface $request): bool
{
return true;
}
public function userCanPresent(string $accessToken, Document $document, RequestInterface $request): bool
{
return $this->isTokenValid($accessToken, $document, $request);
}
public function userCanRead(string $accessToken, Document $document, RequestInterface $request): bool
{
return $this->isTokenValid($accessToken, $document, $request);
}
public function userCanRename(string $accessToken, Document $document, RequestInterface $request): bool
{
return false;
}
public function userCanWrite(string $accessToken, Document $document, RequestInterface $request): bool
{
return $this->isTokenValid($accessToken, $document, $request);
}
}

View File

@@ -24,11 +24,12 @@ use loophp\psr17\Psr17Interface;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface; use Psr\Http\Message\StreamInterface;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use RuntimeException;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use function strlen; use function strlen;
final class ChillDocumentManager implements DocumentManagerInterface final class ChillDocumentManager implements DocumentManagerInterface
@@ -190,7 +191,12 @@ final class ChillDocumentManager implements DocumentManagerInterface
public function remove(Document $document): void public function remove(Document $document): void
{ {
// TODO: To implement when we have a clearer view and API. throw new RuntimeException('this is not implemented and should not happens');
}
public function rename(Document $document, string $requestedName): void
{
throw new RuntimeException('this is not implemented and should not happens');
} }
public function write(Document $document, array $properties = []): void public function write(Document $document, array $properties = []): void

View File

@@ -13,39 +13,20 @@ namespace Chill\WopiBundle\Service\Wopi;
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface; use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
use ChampsLibres\WopiLib\Contract\Service\WopiInterface; use ChampsLibres\WopiLib\Contract\Service\WopiInterface;
use DateTimeImmutable;
use DateTimeInterface;
use loophp\psr17\Psr17Interface; use loophp\psr17\Psr17Interface;
use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\CacheItemPoolInterface;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserProviderInterface;
use function strlen;
final class ChillWopi implements WopiInterface final class ChillWopi implements WopiInterface
{ {
private CacheItemPoolInterface $cache;
private DocumentManagerInterface $documentManager;
private Psr17Interface $psr17;
private UserProviderInterface $userProvider;
private WopiInterface $wopi; private WopiInterface $wopi;
public function __construct( public function __construct(
CacheItemPoolInterface $cache,
DocumentManagerInterface $documentManager,
Psr17Interface $psr17,
UserProviderInterface $userProvider,
WopiInterface $wopi WopiInterface $wopi
) { ) {
$this->cache = $cache;
$this->documentManager = $documentManager;
$this->psr17 = $psr17;
$this->userProvider = $userProvider;
$this->wopi = $wopi; $this->wopi = $wopi;
} }
@@ -54,55 +35,9 @@ final class ChillWopi implements WopiInterface
?string $accessToken, ?string $accessToken,
RequestInterface $request RequestInterface $request
): ResponseInterface { ): ResponseInterface {
try { return $this->wopi->checkFileInfo($fileId, $accessToken, $request, [
$user = $this->userProvider->loadUserByUsername($accessToken); 'SupportsRename' => false,
} catch (UsernameNotFoundException $e) { ]);
return $this
->psr17
->createResponse(401);
}
// @ TODO : Replace this with a call to decorated object once authentication is done.
$document = $this->documentManager->findByDocumentId($fileId);
$userIdentifier = $user->getUsername();
$userCacheKey = sprintf('wopi_putUserInfo_%s', $userIdentifier);
return $this
->psr17
->createResponse()
->withHeader('Content-Type', 'application/json')
->withBody($this->psr17->createStream((string) json_encode(
[
'BaseFileName' => $this->documentManager->getBasename($document),
'OwnerId' => 'Symfony',
'Size' => $this->documentManager->getSize($document),
'UserId' => $userIdentifier,
'ReadOnly' => false,
'UserCanAttend' => true,
'UserCanPresent' => true,
'UserCanRename' => true,
'UserCanWrite' => true,
'UserCanNotWriteRelative' => false,
'SupportsUserInfo' => true,
'SupportsDeleteFile' => true,
'SupportsLocks' => true,
'SupportsGetLock' => true,
'SupportsExtendedLockLength' => true,
'UserFriendlyName' => $userIdentifier,
'SupportsUpdate' => true,
'SupportsRename' => true,
'SupportsFolder' => false,
'DisablePrint' => false,
'AllowExternalMarketplace' => true,
'SupportedShareUrlTypes' => [
'ReadOnly',
],
'LastModifiedTime' => $this->documentManager->getLastModifiedDate($document)
->format(DateTimeInterface::ATOM),
'SHA256' => $this->documentManager->getSha256($document),
'UserInfo' => (string) $this->cache->getItem($userCacheKey)->get(),
]
)));
} }
public function deleteFile(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface public function deleteFile(string $fileId, ?string $accessToken, RequestInterface $request): ResponseInterface
@@ -152,97 +87,7 @@ final class ChillWopi implements WopiInterface
string $xWopiEditors, string $xWopiEditors,
RequestInterface $request RequestInterface $request
): ResponseInterface { ): ResponseInterface {
$document = $this->documentManager->findByDocumentId($fileId); return $this->wopi->putFile($fileId, $accessToken, $xWopiLock, $xWopiEditors, $request);
$version = $this->documentManager->getVersion($document);
// File is unlocked, we must reject the document, except if collabora is autosaving
if (false === $this->documentManager->hasLock($document) && 'true' !== ($request->getHeader('x-lool-wopi-isexitsave') ?? ['false'])[0]) {
if (0 !== $this->documentManager->getSize($document)) {
return $this
->psr17
->createResponse(409)
->withHeader(
WopiInterface::HEADER_ITEM_VERSION,
sprintf('v%s', $version)
);
}
}
// File is locked, we check for the lock
if ($this->documentManager->hasLock($document)) {
if ($xWopiLock !== $currentLock = $this->documentManager->getLock($document)) {
return $this
->psr17
->createResponse(409)
->withHeader(
WopiInterface::HEADER_LOCK,
$currentLock
)
->withHeader(
WopiInterface::HEADER_ITEM_VERSION,
sprintf('v%s', $version)
);
}
}
// for collabora online editor, check timestamp if present
/* delete because it seems that collabora send always the first wopi-timestamp, not the last known one
// example:
// load the doc: the last-wopi is 12:00 in FileInfo
// save the doc: x-cool-wopi-timestamp is 12:00, but we replace the ts with the time of save (12:05)
// save the doc again: x-cool-wopi-timestamp is still 12:00...
if ($request->hasHeader('x-cool-wopi-timestamp')) {
$date = DateTimeImmutable::createFromFormat(
DateTimeImmutable::ATOM,
$request->getHeader('x-cool-wopi-timestamp')[0]
);
if (false === $date) {
throw new RuntimeException('Error parsing date: ' . implode('', DateTimeImmutable::getLastErrors()));
}
if ($this->documentManager->getLastModifiedDate($document)->getTimestamp() < $date->getTimestamp()) {
return $this
->psr17
->createResponse(409)
->withHeader(
WopiInterface::HEADER_LOCK,
$currentLock
)
->withHeader(
WopiInterface::HEADER_ITEM_VERSION,
sprintf('v%s', $version)
)
->withBody(
$this->psr17->createStream(
json_encode(['COOLStatusCode' => 1010])
)
);
}
}
*/
$body = (string) $request->getBody();
$this->documentManager->write(
$document,
[
'content' => $body,
'size' => (string) strlen($body),
]
);
$version = $this->documentManager->getVersion($document);
return $this
->psr17
->createResponse()
->withHeader(
WopiInterface::HEADER_LOCK,
$xWopiLock
)
->withHeader(
WopiInterface::HEADER_ITEM_VERSION,
sprintf('v%s', $version)
);
} }
public function putRelativeFile(string $fileId, string $accessToken, ?string $suggestedTarget, ?string $relativeTarget, bool $overwriteRelativeTarget, int $size, RequestInterface $request): ResponseInterface public function putRelativeFile(string $fileId, string $accessToken, ?string $suggestedTarget, ?string $relativeTarget, bool $overwriteRelativeTarget, int $size, RequestInterface $request): ResponseInterface

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\WopiBundle\Service\Wopi;
use Chill\MainBundle\Entity\User;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\Security\Core\Security;
class UserManager implements \ChampsLibres\WopiBundle\Contracts\UserManagerInterface
{
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function getUserFriendlyName(string $accessToken, string $fileId, RequestInterface $request): ?string
{
$user = $this->security->getUser();
if (!$user instanceof User) {
return null;
}
return (string) $user->getLabel();
}
public function getUserId(string $accessToken, string $fileId, RequestInterface $request): ?string
{
$user = $this->security->getUser();
if (!$user instanceof User) {
return null;
}
return (string) $user->getId();
}
public function isAnonymousUser(string $accessToken, string $fileId, RequestInterface $request): bool
{
return false;
}
}