diff --git a/CHANGELOG.md b/CHANGELOG.md index 550b6348f..0bc086f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,30 @@ and this project adheres to * [person] householdmemberseditor: fix composition type bug in select form (vuejs) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/543) +* [docgen] add more persons choices in docgen for course: amongst requestor (if person), resources of course (if person), and PersonResource (if person); +* [docgen] add a new context with a list of activities in course +* [docgen] add a comment in budget lines + + +## Test releases + +### 2021-04-07 + +* notification list: move action buttons outside of the toggle +* fix detecting of non-read notification +* filter users which are disabled in search user api +* order query for location and add pagination in list +* allow every person which has part for a workflow to see the workflow page +* able to see the workflow if the evaluation document has been deleted +* hardcode the list of supported mime types for edition with collabora +* list of accompanying course: allow to see the pinned comment in list_item + +### 2021-04-06 * [main] notification toggle read: correct js syntax for compilation in production (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/548) * [parcours] Display of interlocuteurs changed to flex-table in parcours edit page to prevent cut-off of information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/535) * [activity] espace entre les boutons pour supprimer les documents -## Test releases ### continuous release in February and March diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php index 48f750c26..d960a0c21 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php @@ -12,13 +12,20 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Repository; use Chill\ActivityBundle\Entity\Activity; +use Chill\ActivityBundle\Entity\ActivityPresence; +use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +use Chill\MainBundle\Entity\Location; +use Chill\MainBundle\Entity\LocationType; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query\ResultSetMappingBuilder; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Security; @@ -72,6 +79,86 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte ->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy); } + public function findByAccompanyingPeriodSimplified(AccompanyingPeriod $period, ?int $limit = 1000): array + { + $rsm = new ResultSetMappingBuilder($this->em); + + $sql = ' + SELECT + a.id AS activity_id, + date, + CASE WHEN durationtime IS NOT NULL THEN (EXTRACT(EPOCH from durationtime) / 60)::int ELSE 0 END AS durationtimeminute, + attendee_id, + comment_comment, + emergency, + sentreceived, + CASE WHEN traveltime IS NOT NULL THEN (EXTRACT(EPOCH from traveltime) / 60)::int ELSE 0 END AS traveltimeminute, + t.id AS type_id, t.name as type_name, + p.id AS presence_id, p.name AS presence_name, + location.id AS location_id, location.address_id, location.name AS location_name, location.phonenumber1, location.phonenumber2, location.email, + location.locationtype_id, locationtype.title AS locationtype_title, + users.userids AS userids, + thirdparties.thirdpartyids, + persons.personids, + actions.socialactionids, + issues.socialissueids + + FROM activity a + LEFT JOIN chill_main_location location ON a.location_id = location.id + LEFT JOIN chill_main_location_type locationtype ON location.locationtype_id = locationtype.id + LEFT JOIN activitytpresence p ON a.attendee_id = p.id + LEFT JOIN activitytype t ON a.type_id = t.id + LEFT JOIN LATERAL (SELECT jsonb_agg(user_id) userids, activity_id FROM activity_user AS au WHERE a.id = au.activity_id GROUP BY activity_id) AS users ON TRUE + LEFT JOIN LATERAL (SELECT jsonb_agg(thirdparty_id) thirdpartyids, activity_id FROM activity_thirdparty AS au WHERE a.id = au.activity_id GROUP BY activity_id) AS thirdparties ON TRUE + LEFT JOIN LATERAL (SELECT jsonb_agg(person_id) personids, activity_id FROM activity_person AS au WHERE a.id = au.activity_id GROUP BY activity_id) AS persons ON TRUE + LEFT JOIN LATERAL (SELECT jsonb_agg(socialaction_id) socialactionids, activity_id FROM chill_activity_activity_chill_person_socialaction AS au WHERE a.id = au.activity_id GROUP BY activity_id) AS actions ON TRUE + LEFT JOIN LATERAL (SELECT jsonb_agg(socialissue_id) socialissueids, activity_id FROM chill_activity_activity_chill_person_socialissue AS au WHERE a.id = au.activity_id GROUP BY activity_id) AS issues ON TRUE + + WHERE accompanyingperiod_id = ? + ORDER BY a.date DESC, a.id DESC + LIMIT ? + '; + + $rsm + ->addEntityResult(Activity::class, 'a') + ->addFieldResult('a', 'activity_id', 'id') + ->addFieldResult('a', 'date', 'date') + ->addFieldResult('a', 'comment', 'comment') + ->addFieldResult('a', 'sentreceived', 'sentReceived') + ->addFieldResult('a', 'emergency', 'emergency') + ->addJoinedEntityResult(Location::class, 'location', 'a', 'location') + ->addFieldResult('location', 'location_id', 'id') + ->addFieldResult('location', 'location_name', 'name') + ->addFieldResult('location', 'phonenumber1', 'phonenumber1') + ->addFieldResult('location', 'phonenumber2', 'phonenumber2') + ->addFieldResult('location', 'email', 'email') + ->addJoinedEntityResult(LocationType::class, 'locationType', 'location', 'locationType') + ->addFieldResult('locationType', 'locationtype_id', 'id') + ->addFieldResult('locationType', 'locationtype_title', 'title') + ->addJoinedEntityResult(ActivityType::class, 'activityType', 'a', 'activityType') + ->addFieldResult('activityType', 'type_id', 'id') + ->addFieldResult('activityType', 'type_name', 'name') + ->addJoinedEntityResult(ActivityPresence::class, 'activityPresence', 'a', 'attendee') + ->addFieldResult('activityPresence', 'presence_id', 'id') + ->addFieldResult('activityPresence', 'presence_name', 'name') + + // results which cannot be mapped into entity + ->addScalarResult('comment_comment', 'comment', Types::TEXT) + ->addScalarResult('userids', 'userIds', Types::JSON) + ->addScalarResult('thirdpartyids', 'thirdPartyIds', Types::JSON) + ->addScalarResult('personids', 'personIds', Types::JSON) + ->addScalarResult('socialactionids', 'socialActionIds', Types::JSON) + ->addScalarResult('socialissueids', 'socialIssueIds', Types::JSON) + ->addScalarResult('durationtimeminute', 'durationTimeMinute', Types::INTEGER) + ->addScalarResult('traveltimeminute', 'travelTimeMinute', Types::INTEGER); + + $nq = $this->em->createNativeQuery($sql, $rsm); + + $nq->setParameter(0, $period->getId())->setParameter(1, $limit); + + return $nq->getResult(AbstractQuery::HYDRATE_ARRAY); + } + /** * @param array $orderBy * diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php index 56fb112f9..1fc6d22b1 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php @@ -21,6 +21,15 @@ interface ActivityACLAwareRepositoryInterface */ public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array; + /** + * Return a list of activities, simplified as array (not object). + * + * The aim of this method is to get a long list of activities and keep performance. + * + * @return array an array of array, each item representing an activity + */ + public function findByAccompanyingPeriodSimplified(AccompanyingPeriod $period, ?int $limit = 1000): array; + /** * @return Activity[]|array */ diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php new file mode 100644 index 000000000..0a442cec7 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ListActivitiesByAccompanyingPeriodContext.php @@ -0,0 +1,286 @@ +accompanyingPeriodContext = $accompanyingPeriodContext; + $this->activityACLAwareRepository = $activityACLAwareRepository; + $this->normalizer = $normalizer; + $this->personRepository = $personRepository; + $this->socialActionRepository = $socialActionRepository; + $this->socialIssueRepository = $socialIssueRepository; + $this->thirdPartyRepository = $thirdPartyRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->userRepository = $userRepository; + } + + public function adminFormReverseTransform(array $data): array + { + return $this->accompanyingPeriodContext->adminFormReverseTransform($data); + } + + public function adminFormTransform(array $data): array + { + return $this->accompanyingPeriodContext->adminFormTransform($data); + } + + public function buildAdminForm(FormBuilderInterface $builder): void + { + $this->accompanyingPeriodContext->buildAdminForm($builder); + } + + public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void + { + $this->accompanyingPeriodContext->buildPublicForm($builder, $template, $entity); + } + + public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array + { + $data = $this->accompanyingPeriodContext->getData($template, $entity, $contextGenerationData); + + $data['activities'] = $this->getActivitiesSimplified($entity); + + return $data; + } + + public function getDescription(): string + { + return 'docgen.Accompanying period with a list of activities description'; + } + + public function getEntityClass(): string + { + return AccompanyingPeriod::class; + } + + public function getFormData(DocGeneratorTemplate $template, $entity): array + { + return $this->accompanyingPeriodContext->getFormData($template, $entity); + } + + public static function getKey(): string + { + return self::class; + } + + public function getName(): string + { + return 'docgen.Accompanying period with a list of activities'; + } + + public function hasAdminForm(): bool + { + return $this->accompanyingPeriodContext->hasAdminForm(); + } + + public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool + { + return $this->accompanyingPeriodContext->hasPublicForm($template, $entity); + } + + public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void + { + $this->accompanyingPeriodContext->storeGenerated($template, $storedObject, $entity, $contextGenerationData); + } + + private function getActivitiesSimplified(AccompanyingPeriod $period) + { + $activities = + $this->activityACLAwareRepository->findByAccompanyingPeriodSimplified($period); + $results = []; + + foreach ($activities as $row) { + $activity = $row[0]; + + $activity['date'] = $this->normalizer->normalize($activity['date'], 'docgen', [ + AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => DateTime::class, + ]); + + if (null === $activity['location']) { + $activity['location'] = $this->normalizer->normalize(null, 'docgen', [ + AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => Location::class, + ]); + $activity['location']['type'] = 'location'; + } else { + $activity['location']['isNull'] = false; + $activity['location']['type'] = 'location'; + + foreach (['1', '2'] as $key) { + $activity['location']['phonenumber' . $key] = $this->normalizer->normalize( + $activity['location']['phonenumber' . $key], + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => PhoneNumber::class] + ); + } + } + + if (is_numeric($activity['location']['locationType']['id'])) { + $activity['location']['locationType']['title'] = $this->translatableStringHelper->localize( + $activity['location']['locationType']['title'] + ); + $activity['location']['locationType']['isNull'] = false; + $activity['location']['locationType']['type'] = 'locationType'; + } + + if (null !== $activity['activityType']) { + $activity['activityType']['name'] = $this->translatableStringHelper->localize( + $activity['activityType']['name'] + ); + $activity['activityType']['isNull'] = false; + $activity['activityType']['type'] = 'activityType'; + } else { + $activity['activityType'] = $this->normalizer->normalize(null, 'docgen', [ + AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => ActivityType::class, + ]); + } + + if (null !== $activity['attendee']) { + $activity['attendee']['name'] = $this->translatableStringHelper->localize( + $activity['attendee']['name'] + ); + $activity['attendee']['isNull'] = false; + $activity['attendee']['type'] = 'activityPresence'; + } else { + $activity['attendee'] = $this->normalizer->normalize(null, 'docgen', [ + AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => ActivityPresence::class, + ]); + } + + $activity['comment'] = (string) $row['comment']; + $activity['travelTimeMinute'] = $row['travelTimeMinute']; + $activity['durationTimeMinute'] = $row['durationTimeMinute']; + + if (null !== $row['userIds']) { + foreach ($row['userIds'] as $id) { + $activity['users'][] = $this->normalizer->normalize( + $this->userRepository->find($id), + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => User::class] + ); + } + } else { + $activity['users'] = []; + } + + if (null !== $row['personIds']) { + foreach ($row['personIds'] as $id) { + $activity['persons'][] = $this->normalizer->normalize( + $this->personRepository->find($id), + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => Person::class] + ); + } + } else { + $activity['persons'] = []; + } + + if (null !== $row['thirdPartyIds']) { + foreach ($row['thirdPartyIds'] as $id) { + $activity['thirdParties'][] = $this->normalizer->normalize( + $this->thirdPartyRepository->find($id), + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => ThirdParty::class] + ); + } + } else { + $activity['thirdParties'] = []; + } + + if (null !== $row['socialActionIds']) { + foreach ($row['socialActionIds'] as $id) { + $activity['socialActions'][] = $this->normalizer->normalize( + $this->socialActionRepository->find($id), + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => SocialAction::class] + ); + } + } else { + $activity['socialActions'] = []; + } + + if (null !== $row['socialIssueIds']) { + foreach ($row['socialIssueIds'] as $id) { + $activity['socialIssues'][] = $this->normalizer->normalize( + $this->socialIssueRepository->find($id), + 'docgen', + [AbstractNormalizer::GROUPS => ['docgen:read'], 'docgen:expects' => SocialIssue::class] + ); + } + } else { + $activity['socialIssues'] = []; + } + + $results[] = $activity; + } + + return $results; + } +} diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 051497b69..49217dd5d 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -232,3 +232,5 @@ This is the minimal activity data: Activité n° docgen: Activity basic: Echange A basic context for activity: Contexte pour les échanges + Accompanying period with a list of activities: Parcours d'accompagnement avec liste des échanges + Accompanying period with a list of activities description: Ce contexte reprend les informations du parcours, et tous les échanges pour un parcours. Les échanges ne sont pas filtrés. diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php index 8e46feb7b..243cd4749 100644 --- a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php +++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php @@ -25,13 +25,13 @@ use function count; */ class SummaryBudget implements SummaryBudgetInterface { - private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; + private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, type FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; - private const QUERY_CHARGE_BY_PERSON = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; + private const QUERY_CHARGE_BY_PERSON = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, type FROM chill_budget.charge WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; - private const QUERY_RESOURCE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.resource WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; + private const QUERY_RESOURCE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, type FROM chill_budget.resource WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; - private const QUERY_RESOURCE_BY_PERSON = 'select SUM(amount) AS sum, type FROM chill_budget.resource WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; + private const QUERY_RESOURCE_BY_PERSON = 'select SUM(amount) AS sum, string_agg(comment, \'|\') AS comment, type FROM chill_budget.resource WHERE person_id = ? AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; private array $chargeLabels; @@ -110,7 +110,8 @@ class SummaryBudget implements SummaryBudgetInterface $rsm = new ResultSetMapping(); $rsm ->addScalarResult('sum', 'sum') - ->addScalarResult('type', 'type'); + ->addScalarResult('type', 'type') + ->addScalarResult('comment', 'comment'); return $rsm; } @@ -121,7 +122,7 @@ class SummaryBudget implements SummaryBudgetInterface $labels = $this->chargeLabels; return array_combine($keys, array_map(function ($i) use ($labels) { - return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; + return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i]), 'comment' => '']; }, $keys)); } @@ -131,7 +132,7 @@ class SummaryBudget implements SummaryBudgetInterface $labels = $this->resourcesLabels; return array_combine($keys, array_map(function ($i) use ($labels) { - return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; + return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i]), 'comment' => '']; }, $keys)); } @@ -158,6 +159,7 @@ class SummaryBudget implements SummaryBudgetInterface $result[$row['type']] = [ 'sum' => (float) $row['sum'], 'label' => $this->translatableStringHelper->localize($label[$row['type']]), + 'comment' => (string) $row['comment'], ]; } diff --git a/src/Bundle/ChillDocStoreBundle/Templating/WopiEditTwigExtensionRuntime.php b/src/Bundle/ChillDocStoreBundle/Templating/WopiEditTwigExtensionRuntime.php index b31b4c538..a99a7d351 100644 --- a/src/Bundle/ChillDocStoreBundle/Templating/WopiEditTwigExtensionRuntime.php +++ b/src/Bundle/ChillDocStoreBundle/Templating/WopiEditTwigExtensionRuntime.php @@ -16,10 +16,102 @@ use Chill\DocStoreBundle\Entity\StoredObject; use Twig\Environment; use Twig\Extension\RuntimeExtensionInterface; -use function array_key_exists; +use function in_array; final class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface { + public const SUPPORTED_MIMES = [ + 'image/svg+xml', + 'application/vnd.ms-powerpoint', + 'application/vnd.ms-excel', + 'application/vnd.sun.xml.writer', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-flat-xml', + 'application/vnd.sun.xml.calc', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-flat-xml', + 'application/vnd.sun.xml.impress', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.presentation-flat-xml', + 'application/vnd.sun.xml.draw', + 'application/vnd.oasis.opendocument.graphics', + 'application/vnd.oasis.opendocument.graphics-flat-xml', + 'application/vnd.oasis.opendocument.chart', + 'application/vnd.sun.xml.writer.global', + 'application/vnd.oasis.opendocument.text-master', + 'application/vnd.sun.xml.writer.template', + 'application/vnd.oasis.opendocument.text-template', + 'application/vnd.oasis.opendocument.text-master-template', + 'application/vnd.sun.xml.calc.template', + 'application/vnd.oasis.opendocument.spreadsheet-template', + 'application/vnd.sun.xml.impress.template', + 'application/vnd.oasis.opendocument.presentation-template', + 'application/vnd.sun.xml.draw.template', + 'application/vnd.oasis.opendocument.graphics-template', + 'application/msword', + 'application/msword', + 'application/vnd.ms-excel', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-word.document.macroEnabled.12', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'application/vnd.ms-word.template.macroEnabled.12', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'application/vnd.ms-excel.template.macroEnabled.12', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'application/vnd.wordperfect', + 'application/x-aportisdoc', + 'application/x-hwp', + 'application/vnd.ms-works', + 'application/x-mswrite', + 'application/x-dif-document', + 'text/spreadsheet', + 'text/csv', + 'application/x-dbase', + 'application/vnd.lotus-1-2-3', + 'image/cgm', + 'image/vnd.dxf', + 'image/x-emf', + 'image/x-wmf', + 'application/coreldraw', + 'application/vnd.visio2013', + 'application/vnd.visio', + 'application/vnd.ms-visio.drawing', + 'application/x-mspublisher', + 'application/x-sony-bbeb', + 'application/x-gnumeric', + 'application/macwriteii', + 'application/x-iwork-numbers-sffnumbers', + 'application/vnd.oasis.opendocument.text-web', + 'application/x-pagemaker', + 'text/rtf', + 'text/plain', + 'application/x-fictionbook+xml', + 'application/clarisworks', + 'image/x-wpg', + 'application/x-iwork-pages-sffpages', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'application/x-iwork-keynote-sffkey', + + 'application/x-abiword', + 'image/x-freehand', + 'application/vnd.sun.xml.chart', + 'application/x-t602', + 'image/bmp', + 'image/png', + 'image/gif', + 'image/tiff', + 'image/jpg', + 'image/jpeg', + 'application/pdf', + ]; + private const TEMPLATE = '@ChillDocStore/Button/wopi_edit_document.html.twig'; private DiscoveryInterface $discovery; @@ -31,15 +123,7 @@ final class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface public function isEditable(StoredObject $document): bool { - $mime_type = $this->discovery->discoverMimeType($document->getType()); - - foreach ($mime_type as $item) { - if (array_key_exists('default', $item) && 'true' === $item['default']) { - return true; - } - } - - return false; + return in_array($document->getType(), self::SUPPORTED_MIMES, true); } public function renderEditButton(Environment $environment, StoredObject $document, ?array $options = null): string diff --git a/src/Bundle/ChillMainBundle/Controller/LocationController.php b/src/Bundle/ChillMainBundle/Controller/LocationController.php index 10087ec1e..97deac9c5 100644 --- a/src/Bundle/ChillMainBundle/Controller/LocationController.php +++ b/src/Bundle/ChillMainBundle/Controller/LocationController.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; use Chill\MainBundle\CRUD\Controller\CRUDController; +use Chill\MainBundle\Pagination\PaginatorInterface; use Symfony\Component\HttpFoundation\Request; class LocationController extends CRUDController @@ -29,4 +30,9 @@ class LocationController extends CRUDController { $query->where('e.availableForUsers = true'); //TODO not working } + + protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) + { + return $query->addOrderBy('e.name', 'DESC'); + } } diff --git a/src/Bundle/ChillMainBundle/Controller/SearchController.php b/src/Bundle/ChillMainBundle/Controller/SearchController.php index b9f5d19d8..41349336a 100644 --- a/src/Bundle/ChillMainBundle/Controller/SearchController.php +++ b/src/Bundle/ChillMainBundle/Controller/SearchController.php @@ -122,7 +122,7 @@ class SearchController extends AbstractController public function searchAction(Request $request, $_format) { - $pattern = $request->query->get('q', ''); + $pattern = trim($request->query->get('q', '')); if ('' === $pattern) { switch ($_format) { diff --git a/src/Bundle/ChillMainBundle/Resources/public/module/notification/toggle_read.js b/src/Bundle/ChillMainBundle/Resources/public/module/notification/toggle_read.js index 6308f2f11..ae092f8e2 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/module/notification/toggle_read.js +++ b/src/Bundle/ChillMainBundle/Resources/public/module/notification/toggle_read.js @@ -26,7 +26,7 @@ window.addEventListener('DOMContentLoaded', function (e) { buttonClass: el.dataset.buttonClass, buttonNoText: 'false' === el.dataset.buttonText, showUrl: el.dataset.showButtonUrl, - isRead: 1 === el.dataset.notificationCurrentIsRead, + isRead: 1 === Number.parseInt(el.dataset.notificationCurrentIsRead), container: el.dataset.container } }, diff --git a/src/Bundle/ChillMainBundle/Resources/views/Location/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Location/index.html.twig index a04ae73a9..aa883c603 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Location/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Location/index.html.twig @@ -47,6 +47,8 @@ + {{ chill_pagination(paginator) }} +