@lilaquadrat/studio 12.0.0 → 12.2.0

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.
Files changed (140) hide show
  1. package/lib/models.d.ts +8 -1
  2. package/lib/models.js +8 -1
  3. package/lib/models.js.map +1 -1
  4. package/lib/services.d.ts +8 -1
  5. package/lib/services.js +8 -1
  6. package/lib/services.js.map +1 -1
  7. package/lib/src/Immutable.class.js +10 -4
  8. package/lib/src/Immutable.class.js.map +1 -1
  9. package/lib/src/aggegations/structures.aggregation.d.ts +6 -8
  10. package/lib/src/aggegations/structures.aggregation.js +3 -2
  11. package/lib/src/aggegations/structures.aggregation.js.map +1 -1
  12. package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.d.ts +4 -0
  13. package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.js +8 -0
  14. package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.js.map +1 -0
  15. package/lib/src/classes/paymentProviders/StripePaymentProvider.class.d.ts +9 -0
  16. package/lib/src/classes/paymentProviders/StripePaymentProvider.class.js +49 -0
  17. package/lib/src/classes/paymentProviders/StripePaymentProvider.class.js.map +1 -0
  18. package/lib/src/classes/shiftPlanningModel.class.d.ts +6 -0
  19. package/lib/src/classes/shiftPlanningModel.class.js +26 -0
  20. package/lib/src/classes/shiftPlanningModel.class.js.map +1 -0
  21. package/lib/src/helpers/buildProductName.d.ts +7 -0
  22. package/lib/src/helpers/buildProductName.js +20 -0
  23. package/lib/src/helpers/buildProductName.js.map +1 -0
  24. package/lib/src/helpers/shiftPlanningReports.d.ts +7 -0
  25. package/lib/src/helpers/shiftPlanningReports.js +135 -0
  26. package/lib/src/helpers/shiftPlanningReports.js.map +1 -0
  27. package/lib/src/helpers/shiftPlanningSchemas.d.ts +143 -0
  28. package/lib/src/helpers/shiftPlanningSchemas.js +87 -0
  29. package/lib/src/helpers/shiftPlanningSchemas.js.map +1 -0
  30. package/lib/src/helpers/shiftPlanningTime.d.ts +24 -0
  31. package/lib/src/helpers/shiftPlanningTime.js +191 -0
  32. package/lib/src/helpers/shiftPlanningTime.js.map +1 -0
  33. package/lib/src/helpers/shiftPlanningValidation.d.ts +26 -0
  34. package/lib/src/helpers/shiftPlanningValidation.js +53 -0
  35. package/lib/src/helpers/shiftPlanningValidation.js.map +1 -0
  36. package/lib/src/helpers/structureMatch.d.ts +15 -0
  37. package/lib/src/helpers/structureMatch.js +70 -0
  38. package/lib/src/helpers/structureMatch.js.map +1 -0
  39. package/lib/src/interfaces/PaymentProviderBase.d.ts +14 -0
  40. package/lib/src/interfaces/PaymentProviderBase.js +2 -0
  41. package/lib/src/interfaces/PaymentProviderBase.js.map +1 -0
  42. package/lib/src/models/customers.model.js +10 -0
  43. package/lib/src/models/customers.model.js.map +1 -1
  44. package/lib/src/models/employeeAbsence.model.d.ts +4 -0
  45. package/lib/src/models/employeeAbsence.model.js +11 -0
  46. package/lib/src/models/employeeAbsence.model.js.map +1 -0
  47. package/lib/src/models/historySeen.model.d.ts +4 -0
  48. package/lib/src/models/historySeen.model.js +30 -0
  49. package/lib/src/models/historySeen.model.js.map +1 -0
  50. package/lib/src/models/listsParticipants.model.js +11 -0
  51. package/lib/src/models/listsParticipants.model.js.map +1 -1
  52. package/lib/src/models/permissions.model.js +28 -0
  53. package/lib/src/models/permissions.model.js.map +1 -1
  54. package/lib/src/models/shift.model.d.ts +4 -0
  55. package/lib/src/models/shift.model.js +17 -0
  56. package/lib/src/models/shift.model.js.map +1 -0
  57. package/lib/src/models/shiftPlan.model.d.ts +4 -0
  58. package/lib/src/models/shiftPlan.model.js +14 -0
  59. package/lib/src/models/shiftPlan.model.js.map +1 -0
  60. package/lib/src/models/shiftPlanDays.model.d.ts +4 -0
  61. package/lib/src/models/shiftPlanDays.model.js +15 -0
  62. package/lib/src/models/shiftPlanDays.model.js.map +1 -0
  63. package/lib/src/models/shiftPlanningSettings.model.d.ts +4 -0
  64. package/lib/src/models/shiftPlanningSettings.model.js +10 -0
  65. package/lib/src/models/shiftPlanningSettings.model.js.map +1 -0
  66. package/lib/src/models/workAreas.model.d.ts +4 -0
  67. package/lib/src/models/workAreas.model.js +12 -0
  68. package/lib/src/models/workAreas.model.js.map +1 -0
  69. package/lib/src/services/customers.service.d.ts +11 -0
  70. package/lib/src/services/customers.service.js +27 -0
  71. package/lib/src/services/customers.service.js.map +1 -1
  72. package/lib/src/services/employeeAbsences.service.d.ts +18 -0
  73. package/lib/src/services/employeeAbsences.service.js +57 -0
  74. package/lib/src/services/employeeAbsences.service.js.map +1 -0
  75. package/lib/src/services/history.service.d.ts +22 -0
  76. package/lib/src/services/history.service.js +145 -115
  77. package/lib/src/services/history.service.js.map +1 -1
  78. package/lib/src/services/historySeen.service.d.ts +32 -0
  79. package/lib/src/services/historySeen.service.js +66 -0
  80. package/lib/src/services/historySeen.service.js.map +1 -0
  81. package/lib/src/services/listParticipants.service.d.ts +143 -12
  82. package/lib/src/services/listParticipants.service.js +145 -6
  83. package/lib/src/services/listParticipants.service.js.map +1 -1
  84. package/lib/src/services/lists.service.d.ts +9 -0
  85. package/lib/src/services/lists.service.js +28 -0
  86. package/lib/src/services/lists.service.js.map +1 -1
  87. package/lib/src/services/paymentProviders.service.d.ts +5 -0
  88. package/lib/src/services/paymentProviders.service.js +10 -0
  89. package/lib/src/services/paymentProviders.service.js.map +1 -1
  90. package/lib/src/services/shiftPlanDays.service.d.ts +22 -0
  91. package/lib/src/services/shiftPlanDays.service.js +80 -0
  92. package/lib/src/services/shiftPlanDays.service.js.map +1 -0
  93. package/lib/src/services/shiftPlanningSettings.service.d.ts +11 -0
  94. package/lib/src/services/shiftPlanningSettings.service.js +27 -0
  95. package/lib/src/services/shiftPlanningSettings.service.js.map +1 -0
  96. package/lib/src/services/shiftPlans.service.d.ts +24 -0
  97. package/lib/src/services/shiftPlans.service.js +139 -0
  98. package/lib/src/services/shiftPlans.service.js.map +1 -0
  99. package/lib/src/services/shifts.service.d.ts +29 -0
  100. package/lib/src/services/shifts.service.js +260 -0
  101. package/lib/src/services/shifts.service.js.map +1 -0
  102. package/lib/src/services/structures.service.d.ts +2 -0
  103. package/lib/src/services/structures.service.js +7 -0
  104. package/lib/src/services/structures.service.js.map +1 -1
  105. package/lib/src/services/workAreas.service.d.ts +18 -0
  106. package/lib/src/services/workAreas.service.js +67 -0
  107. package/lib/src/services/workAreas.service.js.map +1 -0
  108. package/lib/tests/buildProductName.spec.d.ts +1 -0
  109. package/lib/tests/buildProductName.spec.js +27 -0
  110. package/lib/tests/buildProductName.spec.js.map +1 -0
  111. package/lib/tests/customersServiceStructures.spec.d.ts +1 -0
  112. package/lib/tests/customersServiceStructures.spec.js +146 -0
  113. package/lib/tests/customersServiceStructures.spec.js.map +1 -0
  114. package/lib/tests/historySeenService.spec.d.ts +1 -0
  115. package/lib/tests/historySeenService.spec.js +159 -0
  116. package/lib/tests/historySeenService.spec.js.map +1 -0
  117. package/lib/tests/listParticipantsHistory.spec.js +49 -3
  118. package/lib/tests/listParticipantsHistory.spec.js.map +1 -1
  119. package/lib/tests/listParticipantsPlanning.spec.d.ts +1 -0
  120. package/lib/tests/listParticipantsPlanning.spec.js +83 -0
  121. package/lib/tests/listParticipantsPlanning.spec.js.map +1 -0
  122. package/lib/tests/listParticipantsServiceStructures.spec.d.ts +1 -0
  123. package/lib/tests/listParticipantsServiceStructures.spec.js +176 -0
  124. package/lib/tests/listParticipantsServiceStructures.spec.js.map +1 -0
  125. package/lib/tests/listsServiceCreateExternalProducts.spec.d.ts +1 -0
  126. package/lib/tests/listsServiceCreateExternalProducts.spec.js +73 -0
  127. package/lib/tests/listsServiceCreateExternalProducts.spec.js.map +1 -0
  128. package/lib/tests/paymentProviders.spec.d.ts +1 -0
  129. package/lib/tests/paymentProviders.spec.js +119 -0
  130. package/lib/tests/paymentProviders.spec.js.map +1 -0
  131. package/lib/tests/paymentProvidersServiceGetProduct.spec.d.ts +1 -0
  132. package/lib/tests/paymentProvidersServiceGetProduct.spec.js +33 -0
  133. package/lib/tests/paymentProvidersServiceGetProduct.spec.js.map +1 -0
  134. package/lib/tests/shiftPlanning.spec.d.ts +1 -0
  135. package/lib/tests/shiftPlanning.spec.js +835 -0
  136. package/lib/tests/shiftPlanning.spec.js.map +1 -0
  137. package/lib/tests/structureMatch.spec.d.ts +1 -0
  138. package/lib/tests/structureMatch.spec.js +64 -0
  139. package/lib/tests/structureMatch.spec.js.map +1 -0
  140. package/package.json +2 -2
@@ -0,0 +1,57 @@
1
+ import Immutable from '../Immutable.class.js';
2
+ import ImmutableError from '../classes/errors/Immutable.error.js';
3
+ import AbsenceModel from '../models/employeeAbsence.model.js';
4
+ import CustomersService from './customers.service.js';
5
+ import { interval, planningValidation } from '../helpers/shiftPlanningTime.js';
6
+ import { planningIntervalFilter, planningPage, planningPagination } from '../helpers/shiftPlanningValidation.js';
7
+ /** Absences follow the person across employee lists and departments; a project-local absence would miss conflicts. */
8
+ export class EmployeeAbsencesService extends Immutable {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.model = AbsenceModel;
12
+ }
13
+ async normalizedInput(input, options) {
14
+ if (!(await CustomersService.peopleForPlanning([input.customer], options.company)).length) {
15
+ planningValidation('/customer', 'must identify a person in this company');
16
+ }
17
+ return { ...input, ...interval(input.start, input.end) };
18
+ }
19
+ /** Recording sickness must succeed even if existing shifts need planner attention afterward. */
20
+ async createAbsence(input, options) {
21
+ const normalized = await this.normalizedInput(input, options);
22
+ const created = await this.create({ ...normalized, company: options.company, project: options.project }, options.user, options.app);
23
+ return (await this.singleAbsence(created._id, options));
24
+ }
25
+ async singleAbsence(absence, options) {
26
+ return this.model.db.findOne({ _id: absence, company: options.company, project: options.project });
27
+ }
28
+ async changeAbsence(absence, input, options) {
29
+ if (!await this.singleAbsence(absence, options))
30
+ throw new ImmutableError('EMPLOYEE_ABSENCE_NOT_FOUND');
31
+ const normalized = await this.normalizedInput(input, options);
32
+ await this.immutable({ _id: absence, company: options.company, project: options.project }, normalized, options.user, 'change', options.app);
33
+ return (await this.singleAbsence(absence, options));
34
+ }
35
+ async removeAbsence(absence, options) {
36
+ if (!await this.singleAbsence(absence, options))
37
+ throw new ImmutableError('EMPLOYEE_ABSENCE_NOT_FOUND');
38
+ await this.delete(absence, options.user, options.app);
39
+ }
40
+ async listAbsences(filters, options) {
41
+ const query = { company: options.company, project: options.project, ...planningIntervalFilter(filters) };
42
+ if (filters.customer)
43
+ query.customer = filters.customer;
44
+ const { site, limit, skip } = planningPagination(filters);
45
+ const all = await this.model.db.countDocuments(query);
46
+ const documents = await this.model.db.find(query).sort({ start: 1, _id: 1 }).skip(skip).limit(limit).toArray();
47
+ return planningPage(documents, all, site, limit);
48
+ }
49
+ /** Scheduling checks need company-wide periods; response projections never reveal their private absence type. */
50
+ async absencesForPlanning(customers, from, to, options) {
51
+ return this.model.db.find({ company: options.company, project: options.project, customer: { $in: customers },
52
+ ...planningIntervalFilter({ from, to }),
53
+ }).toArray();
54
+ }
55
+ }
56
+ export default new EmployeeAbsencesService();
57
+ //# sourceMappingURL=employeeAbsences.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"employeeAbsences.service.js","sourceRoot":"","sources":["../../../src/services/employeeAbsences.service.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,16 @@
1
1
  import { Filter, ObjectId, OrderedBulkOperation, UnorderedBulkOperation, Document } from 'mongodb';
2
2
  import { HistoryReason, History, BasicData, Options } from '@lilaquadrat/interfaces';
3
+ import { HistorySeenKey } from './historySeen.service.js';
4
+ type HistoryTenantUser = Pick<HistorySeenKey, 'user' | 'company' | 'project'>;
3
5
  declare class HistoryService {
4
6
  model: import("../classes/modelv2.class.js").default<History, string>;
7
+ /**
8
+ * resolve the author of a history entry to a display name in one lookup.
9
+ * studio accounts live in 'me', member accounts (origin 'member') are linked
10
+ * to their customer through the accounts array, so both are unioned and the
11
+ * entry falls back to the raw account when no profile can be resolved.
12
+ */
13
+ private userLookup;
5
14
  create<T>(data: BasicData<T>, user: string, reason: HistoryReason, app: string, modelName: string): Promise<any>;
6
15
  create<T, S>(data: BasicData<T>, user: string, reason: HistoryReason, app: string, modelName: string, additionalHistoryData?: Record<string, string | number>, copySource?: BasicData<S>): Promise<any>;
7
16
  create<T, S>(data: BasicData<T>, user: string, reason: HistoryReason, app: string, modelName: string, additionalHistoryData?: Record<string, string | number> | undefined, copySource?: BasicData<S>, bulk?: UnorderedBulkOperation | OrderedBulkOperation, origin?: History['history']['origin']): UnorderedBulkOperation | OrderedBulkOperation;
@@ -29,6 +38,19 @@ declare class HistoryService {
29
38
  countQuery: Filter<History>;
30
39
  aggregation: any[];
31
40
  };
41
+ /**
42
+ * the snapshot of one history entry together with the snapshot of the version before it, so the
43
+ * changes can be shown. the first version (0, the creation) has no previous one.
44
+ * the extra filter keeps callers with a narrower permission inside their scope, e.g. a single list.
45
+ */
46
+ entryWithPrevious(company: string, project: string | undefined, historyId: ObjectId, scopeFilter?: Filter<History>): Promise<{
47
+ current: import("mongodb").WithId<History>;
48
+ previous: import("mongodb").WithId<History> | null;
49
+ } | null>;
50
+ /** the whole model of a tenant is the watched scope, entities with a parent use their own scope instead */
51
+ private modelSeenKey;
52
+ unreadCount(options: HistoryTenantUser, model: string): Promise<number>;
53
+ markSeen(options: HistoryTenantUser, model: string): Promise<ObjectId | null>;
32
54
  export(options: Options & {
33
55
  model?: string;
34
56
  }): Promise<import("mongodb").WithId<History>[]>;
@@ -4,10 +4,117 @@ import partialAggregation from '../aggegations/partial.aggregation.js';
4
4
  import { HistoryModel } from '../../models.js';
5
5
  import HistoryError from '../classes/errors/History.error.js';
6
6
  import genericDataAggregation from '../aggegations/genericData.aggregation.js';
7
+ import HistorySeenService from './historySeen.service.js';
7
8
  class HistoryService {
8
9
  constructor() {
9
10
  this.model = HistoryModel;
10
11
  }
12
+ /**
13
+ * resolve the author of a history entry to a display name in one lookup.
14
+ * studio accounts live in 'me', member accounts (origin 'member') are linked
15
+ * to their customer through the accounts array, so both are unioned and the
16
+ * entry falls back to the raw account when no profile can be resolved.
17
+ */
18
+ userLookup() {
19
+ return [
20
+ {
21
+ $lookup: {
22
+ from: 'me',
23
+ as: 'userData',
24
+ let: {
25
+ userid: '$history.user',
26
+ app: '$history.app',
27
+ company: '$company',
28
+ origin: '$history.origin',
29
+ },
30
+ pipeline: [
31
+ {
32
+ $match: {
33
+ $expr: {
34
+ $and: [
35
+ { $eq: ['$id', '$$userid'] },
36
+ { $ne: ['$$origin', 'member'] },
37
+ ],
38
+ },
39
+ },
40
+ },
41
+ {
42
+ $project: {
43
+ prename: 1,
44
+ lastname: 1,
45
+ },
46
+ },
47
+ {
48
+ $unionWith: {
49
+ coll: 'customers',
50
+ pipeline: [
51
+ {
52
+ $match: {
53
+ $expr: {
54
+ $and: [
55
+ { $eq: ['$$origin', 'member'] },
56
+ { $eq: ['$company', '$$company'] },
57
+ {
58
+ $gt: [
59
+ {
60
+ $size: {
61
+ $filter: {
62
+ input: { $ifNull: ['$accounts', []] },
63
+ as: 'account',
64
+ cond: {
65
+ $and: [
66
+ { $eq: ['$$account.account', '$$userid'] },
67
+ { $eq: ['$$account.app', '$$app'] },
68
+ ],
69
+ },
70
+ },
71
+ },
72
+ },
73
+ 0,
74
+ ],
75
+ },
76
+ ],
77
+ },
78
+ },
79
+ },
80
+ {
81
+ $project: {
82
+ prename: 1,
83
+ lastname: '$name',
84
+ },
85
+ },
86
+ ],
87
+ },
88
+ },
89
+ {
90
+ $project: {
91
+ prename: 1,
92
+ lastname: 1,
93
+ _id: 0,
94
+ },
95
+ },
96
+ { $limit: 1 },
97
+ ],
98
+ },
99
+ },
100
+ {
101
+ $unwind: {
102
+ path: '$userData',
103
+ preserveNullAndEmptyArrays: true,
104
+ },
105
+ },
106
+ {
107
+ $addFields: {
108
+ 'history.user': {
109
+ $ifNull: [
110
+ { $concat: ['$userData.lastname', ', ', '$userData.prename'] },
111
+ '$history.user',
112
+ ],
113
+ },
114
+ },
115
+ },
116
+ ];
117
+ }
11
118
  create(data, user, reason, app, modelName, additionalHistoryData, copySource, bulk, origin) {
12
119
  const immutable = {
13
120
  ...data,
@@ -70,42 +177,7 @@ class HistoryService {
70
177
  'history.version': version,
71
178
  },
72
179
  }];
73
- const lookup = [
74
- {
75
- $lookup: {
76
- from: 'me',
77
- as: 'userData',
78
- let: { userid: '$history.user' },
79
- pipeline: [
80
- {
81
- $match: {
82
- $and: [
83
- { $expr: { $eq: ['$id', '$$userid'] } },
84
- ],
85
- },
86
- },
87
- ],
88
- },
89
- },
90
- {
91
- $unwind: {
92
- path: '$userData',
93
- preserveNullAndEmptyArrays: true,
94
- },
95
- },
96
- {
97
- $addFields: {
98
- 'history.user': {
99
- $cond: [
100
- { $eq: ['$history.origin', 'member'] },
101
- '$history.user',
102
- { $concat: ['$userData.lastname', ', ', '$userData.prename'] },
103
- ],
104
- },
105
- },
106
- },
107
- ];
108
- aggregation.push(...lookup, ...partialAggregation, ...childDataAggregation);
180
+ aggregation.push(...this.userLookup(), ...partialAggregation, ...childDataAggregation);
109
181
  return this.model.db.aggregate(aggregation).toArray()
110
182
  .then((single) => single[0]);
111
183
  }
@@ -117,50 +189,7 @@ class HistoryService {
117
189
  _id: id,
118
190
  },
119
191
  }];
120
- const lookup = [
121
- {
122
- $lookup: {
123
- from: 'me',
124
- as: 'userData',
125
- let: { userid: '$history.user' },
126
- pipeline: [
127
- {
128
- $match: {
129
- $and: [
130
- { $expr: { $eq: ['$id', '$$userid'] } },
131
- ],
132
- },
133
- },
134
- {
135
- $project: {
136
- _id: 1,
137
- id: 1,
138
- prename: 1,
139
- lastname: 1,
140
- },
141
- },
142
- ],
143
- },
144
- },
145
- {
146
- $unwind: {
147
- path: '$userData',
148
- preserveNullAndEmptyArrays: true,
149
- },
150
- },
151
- {
152
- $addFields: {
153
- 'history.user': {
154
- $cond: [
155
- { $eq: ['$history.origin', 'member'] },
156
- '$history.user',
157
- { $concat: ['$userData.lastname', ', ', '$userData.prename'] },
158
- ],
159
- },
160
- },
161
- },
162
- ];
163
- aggregation.push(...lookup);
192
+ aggregation.push(...this.userLookup());
164
193
  aggregation.push(...partialAggregation);
165
194
  aggregation.push(...childDataAggregation);
166
195
  aggregation.push(...genericDataAggregation);
@@ -200,41 +229,7 @@ class HistoryService {
200
229
  $limit: limit,
201
230
  },
202
231
  ];
203
- const lookup = [
204
- {
205
- $lookup: {
206
- from: 'me',
207
- as: 'userData',
208
- let: { userid: '$history.user' },
209
- pipeline: [
210
- {
211
- $match: {
212
- $and: [
213
- { $expr: { $eq: ['$id', '$$userid'] } },
214
- ],
215
- },
216
- },
217
- ],
218
- },
219
- },
220
- {
221
- $unwind: {
222
- path: '$userData',
223
- preserveNullAndEmptyArrays: true,
224
- },
225
- },
226
- {
227
- $addFields: {
228
- 'history.user': {
229
- $cond: [
230
- { $eq: ['$history.origin', 'member'] },
231
- '$history.user',
232
- { $concat: ['$userData.lastname', ', ', '$userData.prename'] },
233
- ],
234
- },
235
- },
236
- },
237
- ];
232
+ const lookup = this.userLookup();
238
233
  if (projection) {
239
234
  lookup.push({
240
235
  $project: {
@@ -251,6 +246,41 @@ class HistoryService {
251
246
  aggregation,
252
247
  };
253
248
  }
249
+ /**
250
+ * the snapshot of one history entry together with the snapshot of the version before it, so the
251
+ * changes can be shown. the first version (0, the creation) has no previous one.
252
+ * the extra filter keeps callers with a narrower permission inside their scope, e.g. a single list.
253
+ */
254
+ async entryWithPrevious(company, project, historyId, scopeFilter = {}) {
255
+ const tenant = { company, project: project ?? null };
256
+ const current = await this.model.db.findOne({ ...scopeFilter, ...tenant, _id: historyId });
257
+ if (!current)
258
+ return null;
259
+ const previous = current.history.version > 0
260
+ ? await this.model.db.findOne({
261
+ ...tenant,
262
+ 'history.parent': current.history.parent,
263
+ 'history.version': current.history.version - 1,
264
+ })
265
+ : null;
266
+ return { current, previous };
267
+ }
268
+ /** the whole model of a tenant is the watched scope, entities with a parent use their own scope instead */
269
+ modelSeenKey(options, model) {
270
+ return {
271
+ user: options.user,
272
+ company: options.company,
273
+ project: options.project,
274
+ model,
275
+ scope: model,
276
+ };
277
+ }
278
+ unreadCount(options, model) {
279
+ return HistorySeenService.unreadCount(this.modelSeenKey(options, model), {});
280
+ }
281
+ markSeen(options, model) {
282
+ return HistorySeenService.markSeen(this.modelSeenKey(options, model), {});
283
+ }
254
284
  export(options) {
255
285
  return this.model.db.find({ company: options.company, project: options.project, 'history.model': options.model }).toArray();
256
286
  }
@@ -1 +1 @@
1
- {"version":3,"file":"history.service.js","sourceRoot":"","sources":["../../../src/services/history.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"history.service.js","sourceRoot":"","sources":["../../../src/services/history.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { Filter, ObjectId } from 'mongodb';
2
+ import { History } from '@lilaquadrat/interfaces';
3
+ export interface HistorySeenKey {
4
+ user: string;
5
+ company: string;
6
+ project?: string;
7
+ model: string;
8
+ scope: string;
9
+ }
10
+ declare class HistorySeenService {
11
+ /** bounds the cost of counting a long unseen history, callers display anything at the limit as "limit+" */
12
+ readonly countLimit = 100;
13
+ /**
14
+ * restricts the history to the watched scope. tenant and model keys are applied last
15
+ * so a caller supplied filter can never widen the query beyond the key.
16
+ */
17
+ private historyFilter;
18
+ private markerKey;
19
+ /**
20
+ * number of history entries newer than the marker of the user, up to countLimit.
21
+ * entries written by the user themselves are not news to them. without a marker everything is unread.
22
+ */
23
+ unreadCount(key: HistorySeenKey, scopeFilter: Filter<History>): Promise<number>;
24
+ /**
25
+ * moves the marker to the newest history entry that exists right now. resolved on the server so
26
+ * entries written between loading the screen and calling this are not marked as seen by accident.
27
+ * the marker only ever moves forward.
28
+ */
29
+ markSeen(key: HistorySeenKey, scopeFilter: Filter<History>): Promise<ObjectId | null>;
30
+ }
31
+ declare const _default: HistorySeenService;
32
+ export default _default;
@@ -0,0 +1,66 @@
1
+ import HistoryModel from '../models/history.model.js';
2
+ import HistorySeenModel from '../models/historySeen.model.js';
3
+ class HistorySeenService {
4
+ constructor() {
5
+ /** bounds the cost of counting a long unseen history, callers display anything at the limit as "limit+" */
6
+ this.countLimit = 100;
7
+ }
8
+ /**
9
+ * restricts the history to the watched scope. tenant and model keys are applied last
10
+ * so a caller supplied filter can never widen the query beyond the key.
11
+ */
12
+ historyFilter(key, scopeFilter) {
13
+ const filter = {
14
+ ...scopeFilter,
15
+ company: key.company,
16
+ 'history.model': key.model,
17
+ };
18
+ if (key.project)
19
+ filter.project = key.project;
20
+ return filter;
21
+ }
22
+ markerKey(key) {
23
+ const markerKey = {
24
+ user: key.user,
25
+ company: key.company,
26
+ model: key.model,
27
+ scope: key.scope,
28
+ };
29
+ if (key.project)
30
+ markerKey.project = key.project;
31
+ return markerKey;
32
+ }
33
+ /**
34
+ * number of history entries newer than the marker of the user, up to countLimit.
35
+ * entries written by the user themselves are not news to them. without a marker everything is unread.
36
+ */
37
+ async unreadCount(key, scopeFilter) {
38
+ const marker = await HistorySeenModel.db.findOne(this.markerKey(key), { projection: { lastSeenId: 1 } });
39
+ const filter = this.historyFilter(key, scopeFilter);
40
+ filter['history.user'] = { $ne: key.user };
41
+ if (marker?.lastSeenId)
42
+ filter._id = { $gt: marker.lastSeenId };
43
+ return HistoryModel.db.countDocuments(filter, { limit: this.countLimit });
44
+ }
45
+ /**
46
+ * moves the marker to the newest history entry that exists right now. resolved on the server so
47
+ * entries written between loading the screen and calling this are not marked as seen by accident.
48
+ * the marker only ever moves forward.
49
+ */
50
+ async markSeen(key, scopeFilter) {
51
+ const [newest] = await HistoryModel.db
52
+ .find(this.historyFilter(key, scopeFilter), { projection: { _id: 1 } })
53
+ .sort({ _id: -1 })
54
+ .limit(1)
55
+ .toArray();
56
+ if (!newest)
57
+ return null;
58
+ await HistorySeenModel.db.updateOne(this.markerKey(key), {
59
+ $max: { lastSeenId: newest._id },
60
+ $set: { seenAt: new Date() },
61
+ }, { upsert: true });
62
+ return newest._id;
63
+ }
64
+ }
65
+ export default new HistorySeenService();
66
+ //# sourceMappingURL=historySeen.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historySeen.service.js","sourceRoot":"","sources":["../../../src/services/historySeen.service.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,4BAA4B,CAAC;AACtD,OAAO,gBAAgB,MAAM,gCAAgC,CAAC;AAU9D,MAAM,kBAAkB;IAAxB;QAEE,2GAA2G;QAClG,eAAU,GAAG,GAAG,CAAC;IAgF5B,CAAC;IA9EC;;;OAGG;IACK,aAAa,CAAC,GAAmB,EAAE,WAA4B;QAErE,MAAM,MAAM,GAAoB;YAC9B,GAAG,WAAW;YACd,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,eAAe,EAAE,GAAG,CAAC,KAAK;SAC3B,CAAC;QAEF,IAAI,GAAG,CAAC,OAAO;YAAE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAE9C,OAAO,MAAM,CAAC;IAEhB,CAAC;IAEO,SAAS,CAAC,GAAmB;QAEnC,MAAM,SAAS,GAAwB;YACrC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC;QAEF,IAAI,GAAG,CAAC,OAAO;YAAE,SAAS,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAEjD,OAAO,SAAS,CAAC;IAEnB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,GAAmB,EAAE,WAA4B;QAEjE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACzG,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEpD,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QAE3C,IAAI,MAAM,EAAE,UAAU;YAAE,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QAEhE,OAAO,YAAY,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IAE5E,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAmB,EAAE,WAA4B;QAE9D,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,EAAE;aACnC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;aACtE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;aACjB,KAAK,CAAC,CAAC,CAAC;aACR,OAAO,EAAE,CAAC;QAEb,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,gBAAgB,CAAC,EAAE,CAAC,SAAS,CACjC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EACnB;YACE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,GAAG,EAAE;YAChC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE;SAC7B,EACD,EAAE,MAAM,EAAE,IAAI,EAAE,CACjB,CAAC;QAEF,OAAO,MAAM,CAAC,GAAG,CAAC;IAEpB,CAAC;CAEF;AAED,eAAe,IAAI,kBAAkB,EAAE,CAAC"}