@things-factory/calendar 10.1.203 → 10.1.205
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/pages/calendar/calendar-list-page.d.ts +1 -9
- package/dist-client/pages/calendar/calendar-list-page.js +2 -27
- package/dist-client/pages/calendar/calendar-list-page.js.map +1 -1
- package/dist-client/pages/event/event-list-page.d.ts +5 -28
- package/dist-client/pages/event/event-list-page.js +65 -177
- package/dist-client/pages/event/event-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +0 -3
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +5 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +16 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/attendee/attendee-query.d.ts +7 -4
- package/dist-server/service/attendee/attendee-query.js +34 -25
- package/dist-server/service/attendee/attendee-query.js.map +1 -1
- package/dist-server/service/attendee/attendee-service.d.ts +41 -0
- package/dist-server/service/attendee/attendee-service.js +90 -0
- package/dist-server/service/attendee/attendee-service.js.map +1 -0
- package/dist-server/service/attendee/attendee-type.d.ts +3 -15
- package/dist-server/service/attendee/attendee-type.js +12 -53
- package/dist-server/service/attendee/attendee-type.js.map +1 -1
- package/dist-server/service/attendee/attendee.d.ts +24 -7
- package/dist-server/service/attendee/attendee.js +99 -23
- package/dist-server/service/attendee/attendee.js.map +1 -1
- package/dist-server/service/attendee/index.d.ts +1 -2
- package/dist-server/service/attendee/index.js +1 -2
- package/dist-server/service/attendee/index.js.map +1 -1
- package/dist-server/service/calendar/calendar-mutation.d.ts +1 -3
- package/dist-server/service/calendar/calendar-mutation.js +21 -94
- package/dist-server/service/calendar/calendar-mutation.js.map +1 -1
- package/dist-server/service/calendar/calendar-query.d.ts +1 -1
- package/dist-server/service/calendar/calendar-query.js +15 -17
- package/dist-server/service/calendar/calendar-query.js.map +1 -1
- package/dist-server/service/calendar/calendar-service.d.ts +10 -0
- package/dist-server/service/calendar/calendar-service.js +58 -0
- package/dist-server/service/calendar/calendar-service.js.map +1 -0
- package/dist-server/service/calendar/calendar-type.d.ts +1 -4
- package/dist-server/service/calendar/calendar-type.js +13 -25
- package/dist-server/service/calendar/calendar-type.js.map +1 -1
- package/dist-server/service/calendar/calendar.d.ts +7 -8
- package/dist-server/service/calendar/calendar.js +23 -33
- package/dist-server/service/calendar/calendar.js.map +1 -1
- package/dist-server/service/event/event-mutation.d.ts +6 -4
- package/dist-server/service/event/event-mutation.js +60 -83
- package/dist-server/service/event/event-mutation.js.map +1 -1
- package/dist-server/service/event/event-query.d.ts +11 -1
- package/dist-server/service/event/event-query.js +106 -13
- package/dist-server/service/event/event-query.js.map +1 -1
- package/dist-server/service/event/event-rules.d.ts +10 -0
- package/dist-server/service/event/event-rules.js +38 -0
- package/dist-server/service/event/event-rules.js.map +1 -0
- package/dist-server/service/event/event-service.d.ts +42 -0
- package/dist-server/service/event/event-service.js +159 -0
- package/dist-server/service/event/event-service.js.map +1 -0
- package/dist-server/service/event/event-type.d.ts +10 -11
- package/dist-server/service/event/event-type.js +32 -36
- package/dist-server/service/event/event-type.js.map +1 -1
- package/dist-server/service/event/event.d.ts +25 -11
- package/dist-server/service/event/event.js +89 -36
- package/dist-server/service/event/event.js.map +1 -1
- package/dist-server/service/event-series/event-series-mutation.d.ts +11 -0
- package/dist-server/service/event-series/event-series-mutation.js +100 -0
- package/dist-server/service/event-series/event-series-mutation.js.map +1 -0
- package/dist-server/service/event-series/event-series-query.d.ts +16 -0
- package/dist-server/service/event-series/event-series-query.js +109 -0
- package/dist-server/service/event-series/event-series-query.js.map +1 -0
- package/dist-server/service/event-series/event-series-service.d.ts +40 -0
- package/dist-server/service/event-series/event-series-service.js +253 -0
- package/dist-server/service/event-series/event-series-service.js.map +1 -0
- package/dist-server/service/event-series/event-series-type.d.ts +41 -0
- package/dist-server/service/event-series/event-series-type.js +155 -0
- package/dist-server/service/event-series/event-series-type.js.map +1 -0
- package/dist-server/service/event-series/event-series.d.ts +32 -0
- package/dist-server/service/event-series/event-series.js +134 -0
- package/dist-server/service/event-series/event-series.js.map +1 -0
- package/dist-server/service/event-series/index.d.ts +6 -0
- package/dist-server/service/event-series/index.js +10 -0
- package/dist-server/service/event-series/index.js.map +1 -0
- package/dist-server/service/event-series/recurrence.d.ts +19 -0
- package/dist-server/service/event-series/recurrence.js +95 -0
- package/dist-server/service/event-series/recurrence.js.map +1 -0
- package/dist-server/service/index.d.ts +15 -4
- package/dist-server/service/index.js +29 -11
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -5
- package/tests/open-doors.test.ts +18 -21
- package/things-factory.config.js +0 -4
- package/translations/en.json +44 -1
- package/translations/es.json +44 -1
- package/translations/ja.json +44 -1
- package/translations/ko.json +44 -1
- package/translations/ms.json +44 -1
- package/translations/zh.json +44 -1
- package/concept.md +0 -31
- package/dist-client/pages/attendee/attendee-importer.d.ts +0 -23
- package/dist-client/pages/attendee/attendee-importer.js +0 -93
- package/dist-client/pages/attendee/attendee-importer.js.map +0 -1
- package/dist-client/pages/attendee/attendee-list-page.d.ts +0 -56
- package/dist-client/pages/attendee/attendee-list-page.js +0 -263
- package/dist-client/pages/attendee/attendee-list-page.js.map +0 -1
- package/dist-client/pages/calendar/calendar-importer.d.ts +0 -23
- package/dist-client/pages/calendar/calendar-importer.js +0 -93
- package/dist-client/pages/calendar/calendar-importer.js.map +0 -1
- package/dist-client/pages/event/event-importer.d.ts +0 -23
- package/dist-client/pages/event/event-importer.js +0 -93
- package/dist-client/pages/event/event-importer.js.map +0 -1
- package/dist-server/service/attendee/attendee-mutation.d.ts +0 -10
- package/dist-server/service/attendee/attendee-mutation.js +0 -140
- package/dist-server/service/attendee/attendee-mutation.js.map +0 -1
|
@@ -3,35 +3,70 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.EventQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
|
-
const
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
7
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const attendee_1 = require("../attendee/attendee");
|
|
10
|
+
const calendar_1 = require("../calendar/calendar");
|
|
11
|
+
const event_series_1 = require("../event-series/event-series");
|
|
8
12
|
const event_1 = require("./event");
|
|
9
13
|
const event_type_1 = require("./event-type");
|
|
14
|
+
const event_service_1 = require("./event-service");
|
|
10
15
|
let EventQuery = class EventQuery {
|
|
11
|
-
|
|
12
|
-
return
|
|
13
|
-
where: { id }
|
|
14
|
-
});
|
|
16
|
+
event(id, context) {
|
|
17
|
+
return (0, shell_1.getRepository)(event_1.Event).findOne({ where: { domain: { id: context.state.domain.id }, id } });
|
|
15
18
|
}
|
|
16
19
|
async events(params, context) {
|
|
17
20
|
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
21
|
+
domain: context.state.domain,
|
|
18
22
|
params,
|
|
19
|
-
repository:
|
|
20
|
-
searchables: ['name', 'description']
|
|
23
|
+
repository: (0, shell_1.getRepository)(event_1.Event),
|
|
24
|
+
searchables: ['name', 'description', 'location']
|
|
21
25
|
});
|
|
22
26
|
const [items, total] = await queryBuilder.getManyAndCount();
|
|
23
27
|
return { items, total };
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
eventsBetween(from, to, calendarId, context) {
|
|
30
|
+
if (!(to > from))
|
|
31
|
+
throw new shell_1.Refusal('event-range-invalid', {}, 'The range ends after it starts');
|
|
32
|
+
return (0, shell_1.getRepository)(event_1.Event).find({
|
|
33
|
+
where: { domain: { id: context.state.domain.id }, startAt: (0, typeorm_1.LessThan)(to), endAt: (0, typeorm_1.MoreThan)(from), ...(calendarId ? { calendar: { id: calendarId } } : {}) },
|
|
34
|
+
order: { startAt: 'ASC' }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/*
|
|
38
|
+
* The one door of this module that asks for no calendar privilege: it reads only the caller's own - the events they
|
|
39
|
+
* are named on or responsible for - as a person's work calendar does with their to-dos (worklist activityEvents).
|
|
40
|
+
*/
|
|
41
|
+
myEvents(from, to, context) {
|
|
42
|
+
return (0, event_service_1.myEventsOf)((0, shell_1.getRepository)(event_1.Event).manager, context.state.domain, context.state.user, from, to);
|
|
43
|
+
}
|
|
44
|
+
attendees(event) {
|
|
45
|
+
return (0, shell_1.getRepository)(attendee_1.Attendee).find({ where: { event: { id: event.id } }, order: { createdAt: 'ASC' } });
|
|
46
|
+
}
|
|
47
|
+
series(event) {
|
|
48
|
+
return event.seriesId ? (0, shell_1.getRepository)(event_series_1.EventSeries).findOne({ where: { id: event.seriesId }, withDeleted: true }) : null;
|
|
49
|
+
}
|
|
50
|
+
calendar(event) {
|
|
51
|
+
return event.calendarId ? (0, shell_1.getRepository)(calendar_1.Calendar).findOneBy({ id: event.calendarId }) : null;
|
|
52
|
+
}
|
|
53
|
+
organizer(event) {
|
|
54
|
+
return event.organizerId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: event.organizerId }) : null;
|
|
55
|
+
}
|
|
56
|
+
domain(event) {
|
|
57
|
+
return (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: event.domainId });
|
|
58
|
+
}
|
|
59
|
+
updater(event) {
|
|
60
|
+
return event.updaterId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: event.updaterId }) : null;
|
|
27
61
|
}
|
|
28
|
-
|
|
29
|
-
return
|
|
62
|
+
creator(event) {
|
|
63
|
+
return event.creatorId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: event.creatorId }) : null;
|
|
30
64
|
}
|
|
31
65
|
};
|
|
32
66
|
exports.EventQuery = EventQuery;
|
|
33
67
|
tslib_1.__decorate([
|
|
34
|
-
(0, type_graphql_1.
|
|
68
|
+
(0, type_graphql_1.Directive)('@privilege(category: "calendar", privilege: "query", domainOwnerGranted: true)'),
|
|
69
|
+
(0, type_graphql_1.Query)(returns => event_1.Event, { nullable: true, description: 'To fetch an event' }),
|
|
35
70
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
36
71
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
37
72
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -39,13 +74,70 @@ tslib_1.__decorate([
|
|
|
39
74
|
tslib_1.__metadata("design:returntype", Promise)
|
|
40
75
|
], EventQuery.prototype, "event", null);
|
|
41
76
|
tslib_1.__decorate([
|
|
42
|
-
(0, type_graphql_1.
|
|
77
|
+
(0, type_graphql_1.Directive)('@privilege(category: "calendar", privilege: "query", domainOwnerGranted: true)'),
|
|
78
|
+
(0, type_graphql_1.Query)(returns => event_type_1.EventList, { description: 'To fetch a page of events' }),
|
|
43
79
|
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
44
80
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
45
81
|
tslib_1.__metadata("design:type", Function),
|
|
46
82
|
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
47
83
|
tslib_1.__metadata("design:returntype", Promise)
|
|
48
84
|
], EventQuery.prototype, "events", null);
|
|
85
|
+
tslib_1.__decorate([
|
|
86
|
+
(0, type_graphql_1.Directive)('@privilege(category: "calendar", privilege: "query", domainOwnerGranted: true)'),
|
|
87
|
+
(0, type_graphql_1.Query)(returns => [event_1.Event], { description: 'To fetch the events that overlap a time range, earliest first' }),
|
|
88
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('from')),
|
|
89
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('to')),
|
|
90
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('calendarId', { nullable: true })),
|
|
91
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
92
|
+
tslib_1.__metadata("design:type", Function),
|
|
93
|
+
tslib_1.__metadata("design:paramtypes", [Date,
|
|
94
|
+
Date, String, Object]),
|
|
95
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
96
|
+
], EventQuery.prototype, "eventsBetween", null);
|
|
97
|
+
tslib_1.__decorate([
|
|
98
|
+
(0, type_graphql_1.Query)(returns => [event_1.Event], { description: "The caller's own events that overlap a time range - those they are named on or responsible for, earliest first" }),
|
|
99
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('from')),
|
|
100
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('to')),
|
|
101
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
102
|
+
tslib_1.__metadata("design:type", Function),
|
|
103
|
+
tslib_1.__metadata("design:paramtypes", [Date, Date, Object]),
|
|
104
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
105
|
+
], EventQuery.prototype, "myEvents", null);
|
|
106
|
+
tslib_1.__decorate([
|
|
107
|
+
(0, type_graphql_1.FieldResolver)(type => [attendee_1.Attendee], { description: 'The people named on the event' }),
|
|
108
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
109
|
+
tslib_1.__metadata("design:type", Function),
|
|
110
|
+
tslib_1.__metadata("design:paramtypes", [event_1.Event]),
|
|
111
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
112
|
+
], EventQuery.prototype, "attendees", null);
|
|
113
|
+
tslib_1.__decorate([
|
|
114
|
+
(0, type_graphql_1.FieldResolver)(type => event_series_1.EventSeries, { nullable: true }),
|
|
115
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
116
|
+
tslib_1.__metadata("design:type", Function),
|
|
117
|
+
tslib_1.__metadata("design:paramtypes", [event_1.Event]),
|
|
118
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
119
|
+
], EventQuery.prototype, "series", null);
|
|
120
|
+
tslib_1.__decorate([
|
|
121
|
+
(0, type_graphql_1.FieldResolver)(type => calendar_1.Calendar, { nullable: true }),
|
|
122
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
123
|
+
tslib_1.__metadata("design:type", Function),
|
|
124
|
+
tslib_1.__metadata("design:paramtypes", [event_1.Event]),
|
|
125
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
126
|
+
], EventQuery.prototype, "calendar", null);
|
|
127
|
+
tslib_1.__decorate([
|
|
128
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
129
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
130
|
+
tslib_1.__metadata("design:type", Function),
|
|
131
|
+
tslib_1.__metadata("design:paramtypes", [event_1.Event]),
|
|
132
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
133
|
+
], EventQuery.prototype, "organizer", null);
|
|
134
|
+
tslib_1.__decorate([
|
|
135
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain),
|
|
136
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
137
|
+
tslib_1.__metadata("design:type", Function),
|
|
138
|
+
tslib_1.__metadata("design:paramtypes", [event_1.Event]),
|
|
139
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
140
|
+
], EventQuery.prototype, "domain", null);
|
|
49
141
|
tslib_1.__decorate([
|
|
50
142
|
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User),
|
|
51
143
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
@@ -61,6 +153,7 @@ tslib_1.__decorate([
|
|
|
61
153
|
tslib_1.__metadata("design:returntype", Promise)
|
|
62
154
|
], EventQuery.prototype, "creator", null);
|
|
63
155
|
exports.EventQuery = EventQuery = tslib_1.__decorate([
|
|
156
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
|
|
64
157
|
(0, type_graphql_1.Resolver)(event_1.Event)
|
|
65
158
|
], EventQuery);
|
|
66
159
|
//# sourceMappingURL=event-query.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-query.js","sourceRoot":"","sources":["../../../server/service/event/event-query.ts"],"names":[],"mappings":";;;;AAAA,+
|
|
1
|
+
{"version":3,"file":"event-query.js","sourceRoot":"","sources":["../../../server/service/event/event-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { LessThan, MoreThan } from 'typeorm'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { Attendee } from '../attendee/attendee'\nimport { Calendar } from '../calendar/calendar'\nimport { EventSeries } from '../event-series/event-series'\nimport { Event } from './event'\nimport { EventList } from './event-type'\nimport { myEventsOf } from './event-service'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Event)\nexport class EventQuery {\n @Directive('@privilege(category: \"calendar\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Event, { nullable: true, description: 'To fetch an event' })\n event(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Event> {\n return getRepository(Event).findOne({ where: { domain: { id: context.state.domain.id }, id } })\n }\n\n @Directive('@privilege(category: \"calendar\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EventList, { description: 'To fetch a page of events' })\n async events(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EventList> {\n const queryBuilder = getQueryBuilderFromListParams({\n domain: context.state.domain,\n params,\n repository: getRepository(Event),\n searchables: ['name', 'description', 'location']\n })\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"calendar\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [Event], { description: 'To fetch the events that overlap a time range, earliest first' })\n eventsBetween(\n @Arg('from') from: Date,\n @Arg('to') to: Date,\n @Arg('calendarId', { nullable: true }) calendarId: string,\n @Ctx() context: ResolverContext\n ): Promise<Event[]> {\n if (!(to > from)) throw new Refusal('event-range-invalid', {}, 'The range ends after it starts')\n return getRepository(Event).find({\n where: { domain: { id: context.state.domain.id }, startAt: LessThan(to), endAt: MoreThan(from), ...(calendarId ? { calendar: { id: calendarId } } : {}) },\n order: { startAt: 'ASC' }\n })\n }\n\n /*\n * The one door of this module that asks for no calendar privilege: it reads only the caller's own - the events they\n * are named on or responsible for - as a person's work calendar does with their to-dos (worklist activityEvents).\n */\n @Query(returns => [Event], { description: \"The caller's own events that overlap a time range - those they are named on or responsible for, earliest first\" })\n myEvents(@Arg('from') from: Date, @Arg('to') to: Date, @Ctx() context: ResolverContext): Promise<Event[]> {\n return myEventsOf(getRepository(Event).manager, context.state.domain, context.state.user, from, to)\n }\n\n @FieldResolver(type => [Attendee], { description: 'The people named on the event' })\n attendees(@Root() event: Event): Promise<Attendee[]> {\n return getRepository(Attendee).find({ where: { event: { id: event.id } }, order: { createdAt: 'ASC' } })\n }\n\n @FieldResolver(type => EventSeries, { nullable: true })\n series(@Root() event: Event): Promise<EventSeries> {\n return event.seriesId ? getRepository(EventSeries).findOne({ where: { id: event.seriesId }, withDeleted: true }) : null\n }\n\n @FieldResolver(type => Calendar, { nullable: true })\n calendar(@Root() event: Event): Promise<Calendar> {\n return event.calendarId ? getRepository(Calendar).findOneBy({ id: event.calendarId }) : null\n }\n\n @FieldResolver(type => User, { nullable: true })\n organizer(@Root() event: Event): Promise<User> {\n return event.organizerId ? getRepository(User).findOneBy({ id: event.organizerId }) : null\n }\n\n @FieldResolver(type => Domain)\n domain(@Root() event: Event): Promise<Domain> {\n return getRepository(Domain).findOneBy({ id: event.domainId })\n }\n\n @FieldResolver(type => User)\n updater(@Root() event: Event): Promise<User> {\n return event.updaterId ? getRepository(User).findOneBy({ id: event.updaterId }) : null\n }\n\n @FieldResolver(type => User)\n creator(@Root() event: Event): Promise<User> {\n return event.creatorId ? getRepository(User).findOneBy({ id: event.creatorId }) : null\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Where an event stands. Only `SCHEDULED` is undecided; a series change touches nothing else. */
|
|
2
|
+
export declare enum EventStatus {
|
|
3
|
+
SCHEDULED = "SCHEDULED",
|
|
4
|
+
POSTPONED = "POSTPONED",
|
|
5
|
+
CANCELLED = "CANCELLED",
|
|
6
|
+
HELD = "HELD"
|
|
7
|
+
}
|
|
8
|
+
export declare function statusMove(from: EventStatus, to: EventStatus): boolean;
|
|
9
|
+
/** Nothing has been decided about it — the only kind a series change may move or remove. */
|
|
10
|
+
export declare function isUndecided(status: EventStatus): boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventStatus = void 0;
|
|
4
|
+
exports.statusMove = statusMove;
|
|
5
|
+
exports.isUndecided = isUndecided;
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
/** Where an event stands. Only `SCHEDULED` is undecided; a series change touches nothing else. */
|
|
8
|
+
var EventStatus;
|
|
9
|
+
(function (EventStatus) {
|
|
10
|
+
EventStatus["SCHEDULED"] = "SCHEDULED";
|
|
11
|
+
EventStatus["POSTPONED"] = "POSTPONED";
|
|
12
|
+
EventStatus["CANCELLED"] = "CANCELLED";
|
|
13
|
+
EventStatus["HELD"] = "HELD";
|
|
14
|
+
})(EventStatus || (exports.EventStatus = EventStatus = {}));
|
|
15
|
+
(0, type_graphql_1.registerEnumType)(EventStatus, {
|
|
16
|
+
name: 'EventStatus',
|
|
17
|
+
description: 'Where an event stands: scheduled, postponed to another time, cancelled, or held',
|
|
18
|
+
valuesConfig: {
|
|
19
|
+
SCHEDULED: { description: 'At the time it was given; nothing decided about it yet' },
|
|
20
|
+
POSTPONED: { description: 'Moved to another time; the time the series gave it stays its identity' },
|
|
21
|
+
CANCELLED: { description: 'Will not take place' },
|
|
22
|
+
HELD: { description: 'Took place' }
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const MOVES = {
|
|
26
|
+
[EventStatus.SCHEDULED]: [EventStatus.POSTPONED, EventStatus.CANCELLED, EventStatus.HELD],
|
|
27
|
+
[EventStatus.POSTPONED]: [EventStatus.POSTPONED, EventStatus.CANCELLED, EventStatus.HELD],
|
|
28
|
+
[EventStatus.CANCELLED]: [],
|
|
29
|
+
[EventStatus.HELD]: []
|
|
30
|
+
};
|
|
31
|
+
function statusMove(from, to) {
|
|
32
|
+
return MOVES[from]?.includes(to) ?? false;
|
|
33
|
+
}
|
|
34
|
+
/** Nothing has been decided about it — the only kind a series change may move or remove. */
|
|
35
|
+
function isUndecided(status) {
|
|
36
|
+
return status === EventStatus.SCHEDULED;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=event-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-rules.js","sourceRoot":"","sources":["../../../server/service/event/event-rules.ts"],"names":[],"mappings":";;;AA4BA,gCAEC;AAGD,kCAEC;AAnCD,+CAA+C;AAE/C,kGAAkG;AAClG,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,sCAAuB,CAAA;IACvB,sCAAuB,CAAA;IACvB,sCAAuB,CAAA;IACvB,4BAAa,CAAA;AACf,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAED,IAAA,+BAAgB,EAAC,WAAW,EAAE;IAC5B,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,iFAAiF;IAC9F,YAAY,EAAE;QACZ,SAAS,EAAE,EAAE,WAAW,EAAE,wDAAwD,EAAE;QACpF,SAAS,EAAE,EAAE,WAAW,EAAE,uEAAuE,EAAE;QACnG,SAAS,EAAE,EAAE,WAAW,EAAE,qBAAqB,EAAE;QACjD,IAAI,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE;KACpC;CACF,CAAC,CAAA;AAEF,MAAM,KAAK,GAAuC;IAChD,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC;IACzF,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC;IACzF,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE;IAC3B,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE;CACvB,CAAA;AAED,SAAgB,UAAU,CAAC,IAAiB,EAAE,EAAe;IAC3D,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,CAAA;AAC3C,CAAC;AAED,4FAA4F;AAC5F,SAAgB,WAAW,CAAC,MAAmB;IAC7C,OAAO,MAAM,KAAK,WAAW,CAAC,SAAS,CAAA;AACzC,CAAC","sourcesContent":["import { registerEnumType } from 'type-graphql'\n\n/** Where an event stands. Only `SCHEDULED` is undecided; a series change touches nothing else. */\nexport enum EventStatus {\n SCHEDULED = 'SCHEDULED',\n POSTPONED = 'POSTPONED',\n CANCELLED = 'CANCELLED',\n HELD = 'HELD'\n}\n\nregisterEnumType(EventStatus, {\n name: 'EventStatus',\n description: 'Where an event stands: scheduled, postponed to another time, cancelled, or held',\n valuesConfig: {\n SCHEDULED: { description: 'At the time it was given; nothing decided about it yet' },\n POSTPONED: { description: 'Moved to another time; the time the series gave it stays its identity' },\n CANCELLED: { description: 'Will not take place' },\n HELD: { description: 'Took place' }\n }\n})\n\nconst MOVES: Record<EventStatus, EventStatus[]> = {\n [EventStatus.SCHEDULED]: [EventStatus.POSTPONED, EventStatus.CANCELLED, EventStatus.HELD],\n [EventStatus.POSTPONED]: [EventStatus.POSTPONED, EventStatus.CANCELLED, EventStatus.HELD],\n [EventStatus.CANCELLED]: [],\n [EventStatus.HELD]: []\n}\n\nexport function statusMove(from: EventStatus, to: EventStatus): boolean {\n return MOVES[from]?.includes(to) ?? false\n}\n\n/** Nothing has been decided about it — the only kind a series change may move or remove. */\nexport function isUndecided(status: EventStatus): boolean {\n return status === EventStatus.SCHEDULED\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EntityManager } from 'typeorm';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
import { Domain } from '@things-factory/shell';
|
|
4
|
+
import { AttendeeInput } from '../attendee/attendee-type';
|
|
5
|
+
import { Calendar } from '../calendar/calendar';
|
|
6
|
+
import { Event } from './event';
|
|
7
|
+
import { EventPatch, NewEvent } from './event-type';
|
|
8
|
+
export declare function eventInDomain(tx: EntityManager, domain: Domain, id: string): Promise<Event>;
|
|
9
|
+
/** The calendar to put something on; none when no id is given. */
|
|
10
|
+
export declare function calendarOfDomain(tx: EntityManager, domain: Domain, calendarId?: string | null): Promise<Calendar | null>;
|
|
11
|
+
/** The person responsible must be an activated user who enters the domain — the same answer an attendee gets. */
|
|
12
|
+
export declare function checkOrganizer(tx: EntityManager, domain: Domain, organizerId: string): Promise<User>;
|
|
13
|
+
export declare function checkEventName(name?: string): string;
|
|
14
|
+
/** A one-off event, scheduled at the time it starts. */
|
|
15
|
+
export declare function createEvent(tx: EntityManager, domain: Domain, user: User, input: NewEvent): Promise<Event>;
|
|
16
|
+
/** Name, description, place or the person responsible of one event. Its time and status have their own moves. */
|
|
17
|
+
export declare function updateEvent(tx: EntityManager, domain: Domain, user: User, id: string, patch: EventPatch): Promise<Event>;
|
|
18
|
+
/**
|
|
19
|
+
* Move one event to another time. Only this event moves; `scheduledAt` stays, so the series still knows it and
|
|
20
|
+
* nothing else — other occurrences, other records — changes. The length stays unless an end is given.
|
|
21
|
+
*/
|
|
22
|
+
export declare function postponeEvent(tx: EntityManager, domain: Domain, user: User, id: string, { startAt, endAt, reason }: {
|
|
23
|
+
startAt: Date;
|
|
24
|
+
endAt?: Date;
|
|
25
|
+
reason?: string;
|
|
26
|
+
}): Promise<Event>;
|
|
27
|
+
/** Cancel one event. Only this event changes. */
|
|
28
|
+
export declare function cancelEvent(tx: EntityManager, domain: Domain, user: User, id: string, reason?: string): Promise<Event>;
|
|
29
|
+
/** Record that the event took place. Not before it starts. */
|
|
30
|
+
export declare function markEventHeld(tx: EntityManager, domain: Domain, user: User, id: string, now?: Date): Promise<Event>;
|
|
31
|
+
/** Make the people named on one event exactly these. The series and its other occurrences do not change. */
|
|
32
|
+
export declare function setEventAttendees(tx: EntityManager, domain: Domain, user: User, id: string, inputs: AttendeeInput[]): Promise<Event>;
|
|
33
|
+
/**
|
|
34
|
+
* Delete a one-off event. An occurrence of a series is cancelled instead: deleted, it would come back the next time
|
|
35
|
+
* the series' occurrences are created.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deleteEvent(tx: EntityManager, domain: Domain, user: User, id: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* A person's own events that overlap [from, to) - those they are named on or are responsible for, earliest first.
|
|
40
|
+
* Nothing else of the domain's calendar: being named on an event is what lets one see it, and only it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function myEventsOf(tx: EntityManager, domain: Domain, user: User, from: Date, to: Date): Promise<Event[]>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.eventInDomain = eventInDomain;
|
|
4
|
+
exports.calendarOfDomain = calendarOfDomain;
|
|
5
|
+
exports.checkOrganizer = checkOrganizer;
|
|
6
|
+
exports.checkEventName = checkEventName;
|
|
7
|
+
exports.createEvent = createEvent;
|
|
8
|
+
exports.updateEvent = updateEvent;
|
|
9
|
+
exports.postponeEvent = postponeEvent;
|
|
10
|
+
exports.cancelEvent = cancelEvent;
|
|
11
|
+
exports.markEventHeld = markEventHeld;
|
|
12
|
+
exports.setEventAttendees = setEventAttendees;
|
|
13
|
+
exports.deleteEvent = deleteEvent;
|
|
14
|
+
exports.myEventsOf = myEventsOf;
|
|
15
|
+
const typeorm_1 = require("typeorm");
|
|
16
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
17
|
+
const shell_1 = require("@things-factory/shell");
|
|
18
|
+
const attendee_1 = require("../attendee/attendee");
|
|
19
|
+
const attendee_service_1 = require("../attendee/attendee-service");
|
|
20
|
+
const calendar_service_1 = require("../calendar/calendar-service");
|
|
21
|
+
const event_1 = require("./event");
|
|
22
|
+
const event_rules_1 = require("./event-rules");
|
|
23
|
+
async function eventInDomain(tx, domain, id) {
|
|
24
|
+
const event = await tx.getRepository(event_1.Event).findOne({ where: { id, domain: { id: domain.id } } });
|
|
25
|
+
if (!event)
|
|
26
|
+
throw new shell_1.Refusal('event-not-found', {}, 'Event not found');
|
|
27
|
+
return event;
|
|
28
|
+
}
|
|
29
|
+
/** The calendar to put something on; none when no id is given. */
|
|
30
|
+
async function calendarOfDomain(tx, domain, calendarId) {
|
|
31
|
+
return calendarId ? (0, calendar_service_1.calendarInDomain)(tx, domain, calendarId) : null;
|
|
32
|
+
}
|
|
33
|
+
/** The person responsible must be an activated user who enters the domain — the same answer an attendee gets. */
|
|
34
|
+
async function checkOrganizer(tx, domain, organizerId) {
|
|
35
|
+
const organizer = await tx.getRepository(auth_base_1.User).findOne({ where: { id: organizerId } });
|
|
36
|
+
if (!organizer || organizer.status !== auth_base_1.UserStatus.ACTIVATED || !(await (0, auth_base_1.entersDomainAsAssignee)(domain, organizer, tx)))
|
|
37
|
+
throw new shell_1.Refusal('event-organizer-invalid', {}, 'Put it in the charge of a user of this domain');
|
|
38
|
+
return organizer;
|
|
39
|
+
}
|
|
40
|
+
function checkEventName(name) {
|
|
41
|
+
const trimmed = name?.trim();
|
|
42
|
+
if (!trimmed)
|
|
43
|
+
throw new shell_1.Refusal('event-name-required', {}, 'Name the event');
|
|
44
|
+
return trimmed;
|
|
45
|
+
}
|
|
46
|
+
function checkSpan(startAt, endAt) {
|
|
47
|
+
if (!(startAt instanceof Date) || isNaN(startAt.getTime()) || !(endAt instanceof Date) || isNaN(endAt.getTime()))
|
|
48
|
+
throw new shell_1.Refusal('event-time-required', {}, 'Give when the event starts and ends');
|
|
49
|
+
if (!(endAt > startAt))
|
|
50
|
+
throw new shell_1.Refusal('event-end-before-start', {}, 'The event ends after it starts');
|
|
51
|
+
}
|
|
52
|
+
/** A one-off event, scheduled at the time it starts. */
|
|
53
|
+
async function createEvent(tx, domain, user, input) {
|
|
54
|
+
const name = checkEventName(input.name);
|
|
55
|
+
checkSpan(input.startAt, input.endAt);
|
|
56
|
+
const calendar = await calendarOfDomain(tx, domain, input.calendarId);
|
|
57
|
+
const organizer = input.organizerId && input.organizerId !== user.id ? await checkOrganizer(tx, domain, input.organizerId) : user;
|
|
58
|
+
const attendees = await (0, attendee_service_1.checkAttendees)(tx, domain, input.attendees);
|
|
59
|
+
const repository = tx.getRepository(event_1.Event);
|
|
60
|
+
const saved = await repository.save(repository.create({
|
|
61
|
+
domain,
|
|
62
|
+
calendar,
|
|
63
|
+
series: null,
|
|
64
|
+
scheduledAt: input.startAt,
|
|
65
|
+
startAt: input.startAt,
|
|
66
|
+
endAt: input.endAt,
|
|
67
|
+
status: event_rules_1.EventStatus.SCHEDULED,
|
|
68
|
+
name,
|
|
69
|
+
description: input.description?.trim() || null,
|
|
70
|
+
location: input.location?.trim() || null,
|
|
71
|
+
organizer,
|
|
72
|
+
creator: user,
|
|
73
|
+
updater: user
|
|
74
|
+
}));
|
|
75
|
+
await (0, attendee_service_1.replaceAttendees)(tx, domain, user, { event: saved }, attendees);
|
|
76
|
+
return eventInDomain(tx, domain, saved.id);
|
|
77
|
+
}
|
|
78
|
+
/** Name, description, place or the person responsible of one event. Its time and status have their own moves. */
|
|
79
|
+
async function updateEvent(tx, domain, user, id, patch) {
|
|
80
|
+
const event = await eventInDomain(tx, domain, id);
|
|
81
|
+
const change = { updater: user };
|
|
82
|
+
if (patch.name !== undefined)
|
|
83
|
+
change.name = checkEventName(patch.name);
|
|
84
|
+
if (patch.description !== undefined)
|
|
85
|
+
change.description = patch.description?.trim() || null;
|
|
86
|
+
if (patch.location !== undefined)
|
|
87
|
+
change.location = patch.location?.trim() || null;
|
|
88
|
+
if (patch.organizerId !== undefined && patch.organizerId !== event.organizerId)
|
|
89
|
+
change.organizer = patch.organizerId ? await checkOrganizer(tx, domain, patch.organizerId) : null;
|
|
90
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, change);
|
|
91
|
+
return eventInDomain(tx, domain, id);
|
|
92
|
+
}
|
|
93
|
+
function checkMove(event, to) {
|
|
94
|
+
if (!(0, event_rules_1.statusMove)(event.status, to))
|
|
95
|
+
throw new shell_1.Refusal('event-status-move-invalid', { from: event.status, to }, 'The event cannot move to that status');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Move one event to another time. Only this event moves; `scheduledAt` stays, so the series still knows it and
|
|
99
|
+
* nothing else — other occurrences, other records — changes. The length stays unless an end is given.
|
|
100
|
+
*/
|
|
101
|
+
async function postponeEvent(tx, domain, user, id, { startAt, endAt, reason }) {
|
|
102
|
+
const event = await eventInDomain(tx, domain, id);
|
|
103
|
+
checkMove(event, event_rules_1.EventStatus.POSTPONED);
|
|
104
|
+
const end = endAt ?? (startAt instanceof Date ? new Date(startAt.getTime() + (event.endAt.getTime() - event.startAt.getTime())) : undefined);
|
|
105
|
+
checkSpan(startAt, end);
|
|
106
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, { startAt, endAt: end, status: event_rules_1.EventStatus.POSTPONED, statusReason: reason?.trim() || null, updater: user });
|
|
107
|
+
return eventInDomain(tx, domain, id);
|
|
108
|
+
}
|
|
109
|
+
/** Cancel one event. Only this event changes. */
|
|
110
|
+
async function cancelEvent(tx, domain, user, id, reason) {
|
|
111
|
+
const event = await eventInDomain(tx, domain, id);
|
|
112
|
+
checkMove(event, event_rules_1.EventStatus.CANCELLED);
|
|
113
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, { status: event_rules_1.EventStatus.CANCELLED, statusReason: reason?.trim() || null, updater: user });
|
|
114
|
+
return eventInDomain(tx, domain, id);
|
|
115
|
+
}
|
|
116
|
+
/** Record that the event took place. Not before it starts. */
|
|
117
|
+
async function markEventHeld(tx, domain, user, id, now = new Date()) {
|
|
118
|
+
const event = await eventInDomain(tx, domain, id);
|
|
119
|
+
checkMove(event, event_rules_1.EventStatus.HELD);
|
|
120
|
+
if (event.startAt > now)
|
|
121
|
+
throw new shell_1.Refusal('event-not-started', {}, 'An event is held only once it has started');
|
|
122
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, { status: event_rules_1.EventStatus.HELD, updater: user });
|
|
123
|
+
return eventInDomain(tx, domain, id);
|
|
124
|
+
}
|
|
125
|
+
/** Make the people named on one event exactly these. The series and its other occurrences do not change. */
|
|
126
|
+
async function setEventAttendees(tx, domain, user, id, inputs) {
|
|
127
|
+
const event = await eventInDomain(tx, domain, id);
|
|
128
|
+
await (0, attendee_service_1.replaceAttendees)(tx, domain, user, { event }, await (0, attendee_service_1.checkAttendees)(tx, domain, inputs));
|
|
129
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, { updater: user });
|
|
130
|
+
return eventInDomain(tx, domain, id);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Delete a one-off event. An occurrence of a series is cancelled instead: deleted, it would come back the next time
|
|
134
|
+
* the series' occurrences are created.
|
|
135
|
+
*/
|
|
136
|
+
async function deleteEvent(tx, domain, user, id) {
|
|
137
|
+
const event = await eventInDomain(tx, domain, id);
|
|
138
|
+
if (event.seriesId)
|
|
139
|
+
throw new shell_1.Refusal('event-occurrence-not-deleted', {}, 'Cancel an occurrence of a series instead of deleting it');
|
|
140
|
+
await tx.getRepository(event_1.Event).update({ id: event.id }, { updater: user });
|
|
141
|
+
await tx.getRepository(event_1.Event).softDelete({ id: event.id });
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A person's own events that overlap [from, to) - those they are named on or are responsible for, earliest first.
|
|
146
|
+
* Nothing else of the domain's calendar: being named on an event is what lets one see it, and only it.
|
|
147
|
+
*/
|
|
148
|
+
async function myEventsOf(tx, domain, user, from, to) {
|
|
149
|
+
if (!(to > from))
|
|
150
|
+
throw new shell_1.Refusal('event-range-invalid', {}, 'The range ends after it starts');
|
|
151
|
+
const named = await tx.getRepository(attendee_1.Attendee).find({ where: { domain: { id: domain.id }, user: { id: user.id } } });
|
|
152
|
+
const eventIds = named.map(one => one.eventId).filter(Boolean);
|
|
153
|
+
const inRange = { domain: { id: domain.id }, startAt: (0, typeorm_1.LessThan)(to), endAt: (0, typeorm_1.MoreThan)(from) };
|
|
154
|
+
return tx.getRepository(event_1.Event).find({
|
|
155
|
+
where: [{ ...inRange, organizer: { id: user.id } }, ...(eventIds.length ? [{ ...inRange, id: (0, typeorm_1.In)(eventIds) }] : [])],
|
|
156
|
+
order: { startAt: 'ASC' }
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=event-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-service.js","sourceRoot":"","sources":["../../../server/service/event/event-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In, LessThan, MoreThan } from 'typeorm'\n\nimport { entersDomainAsAssignee, User, UserStatus } from '@things-factory/auth-base'\nimport { Domain, Refusal } from '@things-factory/shell'\n\nimport { Attendee } from '../attendee/attendee'\nimport { AttendeeInput } from '../attendee/attendee-type'\nimport { checkAttendees, replaceAttendees } from '../attendee/attendee-service'\nimport { Calendar } from '../calendar/calendar'\nimport { calendarInDomain } from '../calendar/calendar-service'\nimport { Event } from './event'\nimport { EventStatus, statusMove } from './event-rules'\nimport { EventPatch, NewEvent } from './event-type'\n\nexport async function eventInDomain(tx: EntityManager, domain: Domain, id: string): Promise<Event> {\n const event = await tx.getRepository(Event).findOne({ where: { id, domain: { id: domain.id } } })\n if (!event) throw new Refusal('event-not-found', {}, 'Event not found')\n return event\n}\n\n/** The calendar to put something on; none when no id is given. */\nexport async function calendarOfDomain(tx: EntityManager, domain: Domain, calendarId?: string | null): Promise<Calendar | null> {\n return calendarId ? calendarInDomain(tx, domain, calendarId) : null\n}\n\n/** The person responsible must be an activated user who enters the domain — the same answer an attendee gets. */\nexport async function checkOrganizer(tx: EntityManager, domain: Domain, organizerId: string): Promise<User> {\n const organizer = await tx.getRepository(User).findOne({ where: { id: organizerId } })\n if (!organizer || organizer.status !== UserStatus.ACTIVATED || !(await entersDomainAsAssignee(domain, organizer, tx)))\n throw new Refusal('event-organizer-invalid', {}, 'Put it in the charge of a user of this domain')\n return organizer\n}\n\nexport function checkEventName(name?: string): string {\n const trimmed = name?.trim()\n if (!trimmed) throw new Refusal('event-name-required', {}, 'Name the event')\n return trimmed\n}\n\nfunction checkSpan(startAt: Date, endAt: Date) {\n if (!(startAt instanceof Date) || isNaN(startAt.getTime()) || !(endAt instanceof Date) || isNaN(endAt.getTime()))\n throw new Refusal('event-time-required', {}, 'Give when the event starts and ends')\n if (!(endAt > startAt)) throw new Refusal('event-end-before-start', {}, 'The event ends after it starts')\n}\n\n/** A one-off event, scheduled at the time it starts. */\nexport async function createEvent(tx: EntityManager, domain: Domain, user: User, input: NewEvent): Promise<Event> {\n const name = checkEventName(input.name)\n checkSpan(input.startAt, input.endAt)\n const calendar = await calendarOfDomain(tx, domain, input.calendarId)\n const organizer = input.organizerId && input.organizerId !== user.id ? await checkOrganizer(tx, domain, input.organizerId) : user\n const attendees = await checkAttendees(tx, domain, input.attendees)\n\n const repository = tx.getRepository(Event)\n const saved = await repository.save(\n repository.create({\n domain,\n calendar,\n series: null,\n scheduledAt: input.startAt,\n startAt: input.startAt,\n endAt: input.endAt,\n status: EventStatus.SCHEDULED,\n name,\n description: input.description?.trim() || null,\n location: input.location?.trim() || null,\n organizer,\n creator: user,\n updater: user\n })\n )\n await replaceAttendees(tx, domain, user, { event: saved }, attendees)\n return eventInDomain(tx, domain, saved.id)\n}\n\n/** Name, description, place or the person responsible of one event. Its time and status have their own moves. */\nexport async function updateEvent(tx: EntityManager, domain: Domain, user: User, id: string, patch: EventPatch): Promise<Event> {\n const event = await eventInDomain(tx, domain, id)\n const change: Partial<Event> = { updater: user }\n if (patch.name !== undefined) change.name = checkEventName(patch.name)\n if (patch.description !== undefined) change.description = patch.description?.trim() || null\n if (patch.location !== undefined) change.location = patch.location?.trim() || null\n if (patch.organizerId !== undefined && patch.organizerId !== event.organizerId)\n change.organizer = patch.organizerId ? await checkOrganizer(tx, domain, patch.organizerId) : null\n await tx.getRepository(Event).update({ id: event.id }, change)\n return eventInDomain(tx, domain, id)\n}\n\nfunction checkMove(event: Event, to: EventStatus) {\n if (!statusMove(event.status, to)) throw new Refusal('event-status-move-invalid', { from: event.status, to }, 'The event cannot move to that status')\n}\n\n/**\n * Move one event to another time. Only this event moves; `scheduledAt` stays, so the series still knows it and\n * nothing else — other occurrences, other records — changes. The length stays unless an end is given.\n */\nexport async function postponeEvent(\n tx: EntityManager,\n domain: Domain,\n user: User,\n id: string,\n { startAt, endAt, reason }: { startAt: Date; endAt?: Date; reason?: string }\n): Promise<Event> {\n const event = await eventInDomain(tx, domain, id)\n checkMove(event, EventStatus.POSTPONED)\n const end = endAt ?? (startAt instanceof Date ? new Date(startAt.getTime() + (event.endAt.getTime() - event.startAt.getTime())) : undefined)\n checkSpan(startAt, end)\n await tx.getRepository(Event).update(\n { id: event.id },\n { startAt, endAt: end, status: EventStatus.POSTPONED, statusReason: reason?.trim() || null, updater: user }\n )\n return eventInDomain(tx, domain, id)\n}\n\n/** Cancel one event. Only this event changes. */\nexport async function cancelEvent(tx: EntityManager, domain: Domain, user: User, id: string, reason?: string): Promise<Event> {\n const event = await eventInDomain(tx, domain, id)\n checkMove(event, EventStatus.CANCELLED)\n await tx.getRepository(Event).update({ id: event.id }, { status: EventStatus.CANCELLED, statusReason: reason?.trim() || null, updater: user })\n return eventInDomain(tx, domain, id)\n}\n\n/** Record that the event took place. Not before it starts. */\nexport async function markEventHeld(tx: EntityManager, domain: Domain, user: User, id: string, now: Date = new Date()): Promise<Event> {\n const event = await eventInDomain(tx, domain, id)\n checkMove(event, EventStatus.HELD)\n if (event.startAt > now) throw new Refusal('event-not-started', {}, 'An event is held only once it has started')\n await tx.getRepository(Event).update({ id: event.id }, { status: EventStatus.HELD, updater: user })\n return eventInDomain(tx, domain, id)\n}\n\n/** Make the people named on one event exactly these. The series and its other occurrences do not change. */\nexport async function setEventAttendees(tx: EntityManager, domain: Domain, user: User, id: string, inputs: AttendeeInput[]): Promise<Event> {\n const event = await eventInDomain(tx, domain, id)\n await replaceAttendees(tx, domain, user, { event }, await checkAttendees(tx, domain, inputs))\n await tx.getRepository(Event).update({ id: event.id }, { updater: user })\n return eventInDomain(tx, domain, id)\n}\n\n/**\n * Delete a one-off event. An occurrence of a series is cancelled instead: deleted, it would come back the next time\n * the series' occurrences are created.\n */\nexport async function deleteEvent(tx: EntityManager, domain: Domain, user: User, id: string): Promise<boolean> {\n const event = await eventInDomain(tx, domain, id)\n if (event.seriesId) throw new Refusal('event-occurrence-not-deleted', {}, 'Cancel an occurrence of a series instead of deleting it')\n await tx.getRepository(Event).update({ id: event.id }, { updater: user })\n await tx.getRepository(Event).softDelete({ id: event.id })\n return true\n}\n\n/**\n * A person's own events that overlap [from, to) - those they are named on or are responsible for, earliest first.\n * Nothing else of the domain's calendar: being named on an event is what lets one see it, and only it.\n */\nexport async function myEventsOf(tx: EntityManager, domain: Domain, user: User, from: Date, to: Date): Promise<Event[]> {\n if (!(to > from)) throw new Refusal('event-range-invalid', {}, 'The range ends after it starts')\n const named = await tx.getRepository(Attendee).find({ where: { domain: { id: domain.id }, user: { id: user.id } } as any })\n const eventIds = named.map(one => one.eventId).filter(Boolean)\n const inRange = { domain: { id: domain.id }, startAt: LessThan(to), endAt: MoreThan(from) }\n return tx.getRepository(Event).find({\n where: [{ ...inRange, organizer: { id: user.id } }, ...(eventIds.length ? [{ ...inRange, id: In(eventIds) }] : [])] as any,\n order: { startAt: 'ASC' }\n })\n}\n"]}
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Event
|
|
1
|
+
import { AttendeeInput } from '../attendee/attendee-type';
|
|
2
|
+
import { Event } from './event';
|
|
3
3
|
export declare class NewEvent {
|
|
4
4
|
name: string;
|
|
5
5
|
description?: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
location?: string;
|
|
7
|
+
calendarId?: string;
|
|
8
|
+
organizerId?: string;
|
|
9
|
+
startAt: Date;
|
|
10
|
+
endAt: Date;
|
|
11
|
+
attendees?: AttendeeInput[];
|
|
10
12
|
}
|
|
11
13
|
export declare class EventPatch {
|
|
12
|
-
id?: string;
|
|
13
14
|
name?: string;
|
|
14
15
|
description?: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
thumbnail?: FileUpload;
|
|
18
|
-
cuFlag?: string;
|
|
16
|
+
location?: string;
|
|
17
|
+
organizerId?: string;
|
|
19
18
|
}
|
|
20
19
|
export declare class EventList {
|
|
21
20
|
items: Event[];
|