Skip to content

Commit

Permalink
feat(scenes): Add does not contain for Calendar action
Browse files Browse the repository at this point in the history
  • Loading branch information
cicoub13 committed Jan 29, 2025
1 parent c56d552 commit a243f19
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 7 deletions.
1 change: 1 addition & 0 deletions front/src/config/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,7 @@
"nameLabel": "Wenn der Name",
"isExactly": "genau ist",
"contains": "enthält",
"doesNotContain": "enthält nicht",
"startsWith": "beginnt mit",
"endsWith": "endet mit",
"hasAnyName": "einen beliebigen Namen hat",
Expand Down
1 change: 1 addition & 0 deletions front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,7 @@
"nameLabel": "If the name",
"isExactly": "is exactly",
"contains": "contains",
"doesNotContain": "does not contain",
"startsWith": "starts with",
"endsWith": "ends with",
"hasAnyName": "has any name",
Expand Down
1 change: 1 addition & 0 deletions front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,7 @@
"nameLabel": "Si le nom",
"isExactly": "est exactement",
"contains": "contient",
"doesNotContain": "ne contient pas",
"startsWith": "commence par",
"endsWith": "finit par",
"hasAnyName": "a n'importe quel nom",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ class CheckTime extends Component {
<option value="contains">
<Text id="editScene.triggersCard.calendarEventIsComing.contains" />
</option>
<option value="does-not-contain">
<Text id="editScene.triggersCard.calendarEventIsComing.doesNotContain" />
</option>
<option value="starts-with">
<Text id="editScene.triggersCard.calendarEventIsComing.startsWith" />
</option>
Expand Down
6 changes: 6 additions & 0 deletions server/lib/calendar/calendar.findCurrentlyRunningEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ async function findCurrentlyRunningEvent(calendars, calendarEventNameComparator,
[Op.like]: `%${calendarEventName}%`,
};
break;
case 'does-not-contain':
// @ts-ignore
queryParams.where.name = {
[Op.notLike]: `%${calendarEventName}%`,
};
break;
case 'starts-with':
// @ts-ignore
queryParams.where.name = {
Expand Down
35 changes: 29 additions & 6 deletions server/lib/scene/scene.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,12 +440,35 @@ const actionsFunc = {
}
},
[ACTIONS.CALENDAR.IS_EVENT_RUNNING]: async (self, action, scope, columnIndex, rowIndex) => {
// find if one event match the condition
const events = await self.calendar.findCurrentlyRunningEvent(
action.calendars,
action.calendar_event_name_comparator,
action.calendar_event_name,
);
let events = [];
// manage special does-not-contain condition
if (action.calendar_event_name_comparator === 'does-not-contain') {
// we want events containing the word from the condition
const eventThatContainsEventName = await self.calendar.findCurrentlyRunningEvent(
action.calendars,
'contains',
action.calendar_event_name,
);
// if at least one event is found containing the word, we want to stop the scene (so events stays empty)
// otherwise we need to check if there is at least another event not containing the word from condition
if (eventThatContainsEventName.length === 0) {
const eventThatDoesNotContainsEventName = await self.calendar.findCurrentlyRunningEvent(
action.calendars,
'does-not-contain',
action.calendar_event_name,
);

// else we use the other events
events = eventThatDoesNotContainsEventName;
}
} else {
// find if one event match the condition
events = await self.calendar.findCurrentlyRunningEvent(
action.calendars,
action.calendar_event_name_comparator,
action.calendar_event_name,
);
}

const atLeastOneEventFound = events.length > 0;
// If one event was found, and the scene should be stopped in that case
Expand Down
1 change: 1 addition & 0 deletions server/models/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const actionSchema = Joi.array().items(
calendar_event_name_comparator: Joi.string().valid(
'is-exactly',
'contains',
'does-not-contain',
'starts-with',
'ends-with',
'has-any-name',
Expand Down
28 changes: 28 additions & 0 deletions server/test/lib/calendar/calendar.event.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,34 @@ describe('calendar.findCurrentlyRunningEvent', () => {
const eventsId = events.map((e) => e.id);
expect(eventsId).deep.equal(['a2b57b0a-7148-4961-8540-e493104bfd7c']);
});
it('should find event in calendar - does-not-contain', async () => {
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
name: 'my test event',
start: startDate,
end: endDate,
});
await calendar.createEvent('test-calendar', {
id: '3f148ad9-b189-4862-84c3-df26f9bf263a',
name: 'my red event',
start: startDate,
end: endDate,
});
const events = await calendar.findCurrentlyRunningEvent(['test-calendar'], 'does-not-contain', 'red');
const eventsId = events.map((e) => e.id);
expect(eventsId).deep.equal(['a2b57b0a-7148-4961-8540-e493104bfd7c']);
});
it('should find event in calendar - does not contain (rule is inside scene code)', async () => {
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
name: 'my test event',
start: startDate,
end: endDate,
});
const events = await calendar.findCurrentlyRunningEvent(['test-calendar'], 'does-not-contain', 'random');
const eventsId = events.map((e) => e.id);
expect(eventsId).deep.equal(['a2b57b0a-7148-4961-8540-e493104bfd7c']);
});
it('should find event in calendar - starts-with', async () => {
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
Expand Down
126 changes: 125 additions & 1 deletion server/test/lib/scene/actions/scene.action.isEventRunnning.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const Calendar = require('../../../../lib/calendar');
const event = new EventEmitter();

describe('scene.action.isEventRunning', () => {
const calendar = new Calendar();
let calendar = new Calendar();
let clock;
const now = new Date();
const startDate = dayjs(now)
Expand All @@ -24,6 +24,7 @@ describe('scene.action.isEventRunning', () => {
.add(45, 'minute')
.toDate();
beforeEach(async () => {
calendar = new Calendar();
clock = useFakeTimers(now);
});
afterEach(() => {
Expand Down Expand Up @@ -236,4 +237,127 @@ describe('scene.action.isEventRunning', () => {
await chaiAssert.isRejected(promise, AbortScene);
assert.notCalled(message.sendToUser);
});
it('should execute condition is-event-running (does-not-contain), and send message because condition is true', async () => {
const stateManager = new StateManager(event);
const message = {
sendToUser: fake.resolves(null),
};
const scope = {};
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
name: 'my test event',
description: 'my event description',
start: startDate,
end: endDate,
});
await executeActions(
{ stateManager, event, message, calendar },
[
[
{
type: ACTIONS.CALENDAR.IS_EVENT_RUNNING,
calendars: ['test-calendar'],
calendar_event_name_comparator: 'does-not-contain',
calendar_event_name: 'red',
stop_scene_if_event_not_found: true,
stop_scene_if_event_found: false,
},
],
[
{
type: ACTIONS.MESSAGE.SEND,
user: 'pepper',
text: 'hello',
},
],
],
scope,
);
assert.calledWith(message.sendToUser, 'pepper', 'hello');
});
it('should execute condition is-event-running (does-not-contain), and stop because condition is false', async () => {
const stateManager = new StateManager(event);
const message = {
sendToUser: fake.resolves(null),
};
const scope = {};
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
name: 'my red event',
description: 'my event description',
start: startDate,
end: endDate,
});
const promise = executeActions(
{ stateManager, event, message, calendar },
[
[
{
type: ACTIONS.CALENDAR.IS_EVENT_RUNNING,
calendars: ['test-calendar'],
calendar_event_name_comparator: 'does-not-contain',
calendar_event_name: 'red',
stop_scene_if_event_not_found: true,
stop_scene_if_event_found: false,
},
],
[
{
type: ACTIONS.MESSAGE.SEND,
user: 'pepper',
text: 'hello',
},
],
],
scope,
);
await chaiAssert.isRejected(promise, AbortScene);
assert.notCalled(message.sendToUser);
});
it('should execute condition is-event-running (does-not-contain), and stop because condition is false', async () => {
const stateManager = new StateManager(event);
const message = {
sendToUser: fake.resolves(null),
};
const scope = {};
await calendar.createEvent('test-calendar', {
id: 'a2b57b0a-7148-4961-8540-e493104bfd7c',
name: 'my red event',
description: 'my event description',
start: startDate,
end: endDate,
});
await calendar.createEvent('test-calendar', {
id: '3cf3f147-96f6-484e-9655-e676fda4d578',
name: 'my second event',
description: 'my seconde event description',
start: startDate,
end: endDate,
});
const promise = executeActions(
{ stateManager, event, message, calendar },
[
[
{
type: ACTIONS.CALENDAR.IS_EVENT_RUNNING,
calendars: ['test-calendar'],
calendar_event_name_comparator: 'does-not-contain',
calendar_event_name: 'red',
stop_scene_if_event_not_found: true,
stop_scene_if_event_found: false,
},
],
[
{
type: ACTIONS.MESSAGE.SEND,
user: 'pepper',
text: 'hello',
},
],
],
scope,
);
await chaiAssert.isRejected(promise, AbortScene);
assert.notCalled(message.sendToUser);
});
});

0 comments on commit a243f19

Please sign in to comment.