Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

- [#233](https://github.com/os2display/display-api-service/pull/233)
- Added calendar api feed source tests for modifiers.
- Changed to use PCRE pattern instead of custom pattern building and fixed modifier bugs for calendar api feed source.
- [#229](https://github.com/os2display/display-api-service/pull/229)
- Adds options to set paths to component and admin files from path to the json config file.
- [#225](https://github.com/os2display/display-api-service/pull/225)
Expand Down
30 changes: 13 additions & 17 deletions docs/calender-api-feed.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,20 +136,19 @@ Modifiers can be set up to modify the output of the feed.

Two types of modifiers are available:

* EXCLUDE_IF_TITLE_NOT_CONTAINS: Removes entries from the feed if the title not contain the trigger word.
* REPLACE_TITLE_IF_CONTAINS: Changes the title if it contains the trigger word.
* EXCLUDE_IF_TITLE_NOT_CONTAINS: Removes entries from the feed if the title does not contain the pattern.
* REPLACE_TITLE_IF_CONTAINS: Changes the title if it contains the pattern.

Parameters:

* type: EXCLUDE_IF_TITLE_NOT_CONTAINS or REPLACE_TITLE_IF_CONTAINS
* id: Unique identifier for the modifier.
* title: Display name when showing the modifier in the admin.
* description: Help text for the modifier.
* description: Description of the modifier.
* activateInFeed: Should this filter be optional? If false the rule will always apply.
* trigger: The string that should trigger the modifier.
* replacement: The string to replace the title with.
* removeTrigger: Should the trigger word be filtered from the title?
* caseSensitive: Should the trigger word be case-sensitive?
* pattern: The PCRE regular expression. See <https://www.php.net/manual/en/reference.pcre.pattern.syntax.php>.
* replacement: The string to replace the title with. See <https://www.php.net/manual/en/function.preg-replace.php>.

Examples of modifiers:

Expand All @@ -161,29 +160,26 @@ Examples of modifiers:
"title": "Vis kun begivenheder med (liste) i titlen.",
"description": "Denne mulighed fjerner begivenheder, der IKKE har (liste) i titlen. Den fjerner også (liste) fra titlen.",
"activateInFeed": true,
"trigger": "(liste)",
"removeTrigger": true,
"caseSensitive": false
"pattern": "\/\\(liste\\)\/i",
"removeTrigger": true
},
{
"type": "REPLACE_TITLE_IF_CONTAINS",
"id": "replaceIfContainsOptaget",
"activateInFeed": false,
"trigger": "(optaget)",
"id": "replaceIfContainsOptaget",
"pattern": "\/\\(optaget\\)\/i",
"replacement": "Optaget",
"removeTrigger": true,
"caseSensitive": false
"removeTrigger": true
},
{
"type": "REPLACE_TITLE_IF_CONTAINS",
"id": "onlyShowAsOptaget",
"activateInFeed": true,
"id": "onlyShowAsOptaget",
"title": "Overskriv alle titler med Optaget",
"description": "Denne mulighed viser alle titler som Optaget.",
"trigger": "",
"pattern": "\/\/",
"replacement": "Optaget",
"removeTrigger": false,
"caseSensitive": false
"removeTrigger": false
}
]
```
116 changes: 64 additions & 52 deletions src/Feed/CalendarApiFeedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ public function __construct(
public function getData(Feed $feed): array
{
try {
$results = [];

$configuration = $feed->getConfiguration();

$enabledModifiers = $configuration['enabledModifiers'] ?? [];
Expand All @@ -76,62 +74,28 @@ public function getData(Feed $feed): array
}

$resources = $configuration['resources'];
foreach ($resources as $resource) {
$events = $this->getResourceEvents($resource);

/** @var CalendarEvent $event */
foreach ($events as $event) {
$title = $event->title;

// Modify title according to event modifiers.
foreach ($this->eventModifiers as $modifier) {
// Make it configurable in the Feed if the modifiers should be enabled.
if ($modifier['activateInFeed'] && !in_array($modifier['id'], $enabledModifiers)) {
continue;
}

if (self::EXCLUDE_IF_TITLE_NOT_CONTAINS == $modifier['type']) {
$match = preg_match('/'.$modifier['trigger'].'/'.(!$modifier['caseSensitive'] ? 'i' : ''), $title);

if ($modifier['removeTrigger']) {
$title = str_replace($modifier['trigger'], '', $title);
}

if (!$match) {
continue;
}
}

if (self::REPLACE_TITLE_IF_CONTAINS == $modifier['type']) {
$match = preg_match('/'.$modifier['trigger'].'/'.(!$modifier['caseSensitive'] ? 'i' : ''), $title);

if ($modifier['removeTrigger']) {
$title = str_replace($modifier['trigger'], '', $title);
}

if ($match) {
$title = $modifier['replacement'];
}
}
}

$title = trim($title);
$events = [];

$results[] = [
'id' => Ulid::generate(),
'title' => $title,
'startTime' => $event->startTimeTimestamp,
'endTime' => $event->endTimeTimestamp,
'resourceTitle' => $event->resourceDisplayName,
'resourceId' => $event->resourceId,
];
}
foreach ($resources as $resource) {
$events += $this->getResourceEvents($resource);
}

$modifiedResults = static::applyModifiersToEvents($events, $this->eventModifiers, $enabledModifiers);

$resultsAsArray = array_map(fn (CalendarEvent $event) => [
'id' => Ulid::generate(),
'title' => $event->title,
'startTime' => $event->startTimeTimestamp,
'endTime' => $event->endTimeTimestamp,
'resourceTitle' => $event->resourceDisplayName,
'resourceId' => $event->resourceId,
], $modifiedResults);

// Sort bookings by start time.
usort($results, fn (array $a, array $b) => $a['startTime'] > $b['startTime'] ? 1 : -1);
usort($resultsAsArray, fn (array $a, array $b) => $a['startTime'] > $b['startTime'] ? 1 : -1);

return $results;
return $resultsAsArray;
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
Expand All @@ -142,6 +106,54 @@ public function getData(Feed $feed): array
return [];
}

public static function applyModifiersToEvents(array $events, array $eventModifiers, array $enabledModifiers): array
{
$results = [];

/** @var CalendarEvent $event */
foreach ($events as $event) {
$title = $event->title;

// Modify title according to event modifiers.
foreach ($eventModifiers as $modifier) {
// Make it configurable in the Feed if the modifiers should be enabled.
if ($modifier['activateInFeed'] && !in_array($modifier['id'], $enabledModifiers)) {
continue;
}

$pattern = $modifier['pattern'];

if (self::EXCLUDE_IF_TITLE_NOT_CONTAINS == $modifier['type']) {
$match = preg_match($pattern, $title);

if (!$match) {
continue 2;
}

if ($modifier['removeTrigger']) {
$title = preg_replace($pattern, '', $title);
}
}

if (self::REPLACE_TITLE_IF_CONTAINS == $modifier['type']) {
$match = preg_match($pattern, $title);

if ($match) {
$title = $modifier['replacement'];
}
}
}

$title = trim($title);

$event->title = $title;

$results[] = $event;
}

return $results;
}

/**
* {@inheritDoc}
*/
Expand Down
79 changes: 79 additions & 0 deletions tests/Feed/CalendarApiFeedTypeData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

declare(strict_types=1);

namespace App\Tests\Feed;

use App\Model\CalendarEvent;

class CalendarApiFeedTypeData
{
public array $events = [];
public array $modifiers = [];

public function __construct()
{
$this->events[] = new CalendarEvent(
'id1',
'title1',
1,
2,
'resourse1',
'Resource 1'
);
$this->events[] = new CalendarEvent(
'id2',
'title2 (optaget)',
3,
4,
'resourse1',
'Resource 1'
);
$this->events[] = new CalendarEvent(
'id3',
'title3 (lISTe)',
5,
6,
'resourse1',
'Resource 1'
);
$this->events[] = new CalendarEvent(
'id4',
'title4 (lISTe) (optaGET)',
7,
8,
'resourse1',
'Resource 1'
);

$this->modifiers[] = [
'type' => 'EXCLUDE_IF_TITLE_NOT_CONTAINS',
'id' => 'excludeIfNotContainsListe',
'title' => 'Vis kun begivenheder med (liste) i titlen.',
'description' => 'Denne mulighed fjerner begivenheder, der IKKE har (liste) i titlen. Den fjerner også (liste) fra titlen.',
'activateInFeed' => true,
'pattern' => '/\(liste\)/i',
'removeTrigger' => true,
];

$this->modifiers[] = [
'type' => 'REPLACE_TITLE_IF_CONTAINS',
'activateInFeed' => false,
'id' => 'replaceIfContainsOptaget',
'pattern' => '/\(optaget\)/i',
'replacement' => 'Optaget',
'removeTrigger' => true,
];

$this->modifiers[] = [
'type' => 'REPLACE_TITLE_IF_CONTAINS',
'activateInFeed' => true,
'id' => 'onlyShowAsOptaget',
'title' => 'Overskriv alle titler med Optaget',
'description' => 'Denne mulighed viser alle titler som Optaget.',
'pattern' => '//',
'replacement' => 'Optaget',
'removeTrigger' => false,
];
}
}
40 changes: 40 additions & 0 deletions tests/Feed/CalendarApiFeedTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace App\Tests\Feed;

use App\Feed\CalendarApiFeedType;
use App\Tests\AbstractBaseApiTestCase;

class CalendarApiFeedTypeTest extends AbstractBaseApiTestCase
{
public function testApplyModifiersToEvents(): void
{
$data = new CalendarApiFeedTypeData();

$result = CalendarApiFeedType::applyModifiersToEvents($data->events, $data->modifiers, ['excludeIfNotContainsListe']);

$this->assertEquals(2, count($result));
$this->assertEquals('title3', $result[0]->title);
$this->assertEquals('Optaget', $result[1]->title);

$data = new CalendarApiFeedTypeData();

$result = CalendarApiFeedType::applyModifiersToEvents($data->events, $data->modifiers, ['onlyShowAsOptaget']);

$this->assertEquals(4, count($result));
$this->assertEquals('Optaget', $result[0]->title);
$this->assertEquals('Optaget', $result[1]->title);
$this->assertEquals('Optaget', $result[2]->title);
$this->assertEquals('Optaget', $result[3]->title);

$data = new CalendarApiFeedTypeData();

$result = CalendarApiFeedType::applyModifiersToEvents($data->events, $data->modifiers, ['excludeIfNotContainsListe', 'onlyShowAsOptaget']);

$this->assertEquals(2, count($result));
$this->assertEquals('Optaget', $result[0]->title);
$this->assertEquals('Optaget', $result[1]->title);
}
}