@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.
- package/lib/models.d.ts +8 -1
- package/lib/models.js +8 -1
- package/lib/models.js.map +1 -1
- package/lib/services.d.ts +8 -1
- package/lib/services.js +8 -1
- package/lib/services.js.map +1 -1
- package/lib/src/Immutable.class.js +10 -4
- package/lib/src/Immutable.class.js.map +1 -1
- package/lib/src/aggegations/structures.aggregation.d.ts +6 -8
- package/lib/src/aggegations/structures.aggregation.js +3 -2
- package/lib/src/aggegations/structures.aggregation.js.map +1 -1
- package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.d.ts +4 -0
- package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.js +8 -0
- package/lib/src/classes/paymentProviders/PaymentProviderFactory.class.js.map +1 -0
- package/lib/src/classes/paymentProviders/StripePaymentProvider.class.d.ts +9 -0
- package/lib/src/classes/paymentProviders/StripePaymentProvider.class.js +49 -0
- package/lib/src/classes/paymentProviders/StripePaymentProvider.class.js.map +1 -0
- package/lib/src/classes/shiftPlanningModel.class.d.ts +6 -0
- package/lib/src/classes/shiftPlanningModel.class.js +26 -0
- package/lib/src/classes/shiftPlanningModel.class.js.map +1 -0
- package/lib/src/helpers/buildProductName.d.ts +7 -0
- package/lib/src/helpers/buildProductName.js +20 -0
- package/lib/src/helpers/buildProductName.js.map +1 -0
- package/lib/src/helpers/shiftPlanningReports.d.ts +7 -0
- package/lib/src/helpers/shiftPlanningReports.js +135 -0
- package/lib/src/helpers/shiftPlanningReports.js.map +1 -0
- package/lib/src/helpers/shiftPlanningSchemas.d.ts +143 -0
- package/lib/src/helpers/shiftPlanningSchemas.js +87 -0
- package/lib/src/helpers/shiftPlanningSchemas.js.map +1 -0
- package/lib/src/helpers/shiftPlanningTime.d.ts +24 -0
- package/lib/src/helpers/shiftPlanningTime.js +191 -0
- package/lib/src/helpers/shiftPlanningTime.js.map +1 -0
- package/lib/src/helpers/shiftPlanningValidation.d.ts +26 -0
- package/lib/src/helpers/shiftPlanningValidation.js +53 -0
- package/lib/src/helpers/shiftPlanningValidation.js.map +1 -0
- package/lib/src/helpers/structureMatch.d.ts +15 -0
- package/lib/src/helpers/structureMatch.js +70 -0
- package/lib/src/helpers/structureMatch.js.map +1 -0
- package/lib/src/interfaces/PaymentProviderBase.d.ts +14 -0
- package/lib/src/interfaces/PaymentProviderBase.js +2 -0
- package/lib/src/interfaces/PaymentProviderBase.js.map +1 -0
- package/lib/src/models/customers.model.js +10 -0
- package/lib/src/models/customers.model.js.map +1 -1
- package/lib/src/models/employeeAbsence.model.d.ts +4 -0
- package/lib/src/models/employeeAbsence.model.js +11 -0
- package/lib/src/models/employeeAbsence.model.js.map +1 -0
- package/lib/src/models/historySeen.model.d.ts +4 -0
- package/lib/src/models/historySeen.model.js +30 -0
- package/lib/src/models/historySeen.model.js.map +1 -0
- package/lib/src/models/listsParticipants.model.js +11 -0
- package/lib/src/models/listsParticipants.model.js.map +1 -1
- package/lib/src/models/permissions.model.js +28 -0
- package/lib/src/models/permissions.model.js.map +1 -1
- package/lib/src/models/shift.model.d.ts +4 -0
- package/lib/src/models/shift.model.js +17 -0
- package/lib/src/models/shift.model.js.map +1 -0
- package/lib/src/models/shiftPlan.model.d.ts +4 -0
- package/lib/src/models/shiftPlan.model.js +14 -0
- package/lib/src/models/shiftPlan.model.js.map +1 -0
- package/lib/src/models/shiftPlanDays.model.d.ts +4 -0
- package/lib/src/models/shiftPlanDays.model.js +15 -0
- package/lib/src/models/shiftPlanDays.model.js.map +1 -0
- package/lib/src/models/shiftPlanningSettings.model.d.ts +4 -0
- package/lib/src/models/shiftPlanningSettings.model.js +10 -0
- package/lib/src/models/shiftPlanningSettings.model.js.map +1 -0
- package/lib/src/models/workAreas.model.d.ts +4 -0
- package/lib/src/models/workAreas.model.js +12 -0
- package/lib/src/models/workAreas.model.js.map +1 -0
- package/lib/src/services/customers.service.d.ts +11 -0
- package/lib/src/services/customers.service.js +27 -0
- package/lib/src/services/customers.service.js.map +1 -1
- package/lib/src/services/employeeAbsences.service.d.ts +18 -0
- package/lib/src/services/employeeAbsences.service.js +57 -0
- package/lib/src/services/employeeAbsences.service.js.map +1 -0
- package/lib/src/services/history.service.d.ts +22 -0
- package/lib/src/services/history.service.js +145 -115
- package/lib/src/services/history.service.js.map +1 -1
- package/lib/src/services/historySeen.service.d.ts +32 -0
- package/lib/src/services/historySeen.service.js +66 -0
- package/lib/src/services/historySeen.service.js.map +1 -0
- package/lib/src/services/listParticipants.service.d.ts +143 -12
- package/lib/src/services/listParticipants.service.js +145 -6
- package/lib/src/services/listParticipants.service.js.map +1 -1
- package/lib/src/services/lists.service.d.ts +9 -0
- package/lib/src/services/lists.service.js +28 -0
- package/lib/src/services/lists.service.js.map +1 -1
- package/lib/src/services/paymentProviders.service.d.ts +5 -0
- package/lib/src/services/paymentProviders.service.js +10 -0
- package/lib/src/services/paymentProviders.service.js.map +1 -1
- package/lib/src/services/shiftPlanDays.service.d.ts +22 -0
- package/lib/src/services/shiftPlanDays.service.js +80 -0
- package/lib/src/services/shiftPlanDays.service.js.map +1 -0
- package/lib/src/services/shiftPlanningSettings.service.d.ts +11 -0
- package/lib/src/services/shiftPlanningSettings.service.js +27 -0
- package/lib/src/services/shiftPlanningSettings.service.js.map +1 -0
- package/lib/src/services/shiftPlans.service.d.ts +24 -0
- package/lib/src/services/shiftPlans.service.js +139 -0
- package/lib/src/services/shiftPlans.service.js.map +1 -0
- package/lib/src/services/shifts.service.d.ts +29 -0
- package/lib/src/services/shifts.service.js +260 -0
- package/lib/src/services/shifts.service.js.map +1 -0
- package/lib/src/services/structures.service.d.ts +2 -0
- package/lib/src/services/structures.service.js +7 -0
- package/lib/src/services/structures.service.js.map +1 -1
- package/lib/src/services/workAreas.service.d.ts +18 -0
- package/lib/src/services/workAreas.service.js +67 -0
- package/lib/src/services/workAreas.service.js.map +1 -0
- package/lib/tests/buildProductName.spec.d.ts +1 -0
- package/lib/tests/buildProductName.spec.js +27 -0
- package/lib/tests/buildProductName.spec.js.map +1 -0
- package/lib/tests/customersServiceStructures.spec.d.ts +1 -0
- package/lib/tests/customersServiceStructures.spec.js +146 -0
- package/lib/tests/customersServiceStructures.spec.js.map +1 -0
- package/lib/tests/historySeenService.spec.d.ts +1 -0
- package/lib/tests/historySeenService.spec.js +159 -0
- package/lib/tests/historySeenService.spec.js.map +1 -0
- package/lib/tests/listParticipantsHistory.spec.js +49 -3
- package/lib/tests/listParticipantsHistory.spec.js.map +1 -1
- package/lib/tests/listParticipantsPlanning.spec.d.ts +1 -0
- package/lib/tests/listParticipantsPlanning.spec.js +83 -0
- package/lib/tests/listParticipantsPlanning.spec.js.map +1 -0
- package/lib/tests/listParticipantsServiceStructures.spec.d.ts +1 -0
- package/lib/tests/listParticipantsServiceStructures.spec.js +176 -0
- package/lib/tests/listParticipantsServiceStructures.spec.js.map +1 -0
- package/lib/tests/listsServiceCreateExternalProducts.spec.d.ts +1 -0
- package/lib/tests/listsServiceCreateExternalProducts.spec.js +73 -0
- package/lib/tests/listsServiceCreateExternalProducts.spec.js.map +1 -0
- package/lib/tests/paymentProviders.spec.d.ts +1 -0
- package/lib/tests/paymentProviders.spec.js +119 -0
- package/lib/tests/paymentProviders.spec.js.map +1 -0
- package/lib/tests/paymentProvidersServiceGetProduct.spec.d.ts +1 -0
- package/lib/tests/paymentProvidersServiceGetProduct.spec.js +33 -0
- package/lib/tests/paymentProvidersServiceGetProduct.spec.js.map +1 -0
- package/lib/tests/shiftPlanning.spec.d.ts +1 -0
- package/lib/tests/shiftPlanning.spec.js +835 -0
- package/lib/tests/shiftPlanning.spec.js.map +1 -0
- package/lib/tests/structureMatch.spec.d.ts +1 -0
- package/lib/tests/structureMatch.spec.js +64 -0
- package/lib/tests/structureMatch.spec.js.map +1 -0
- 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
|
-
|
|
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
|
-
|
|
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":"AACA,OAAO,EAEL,QAAQ,GACT,MAAM,SAAS,CAAC;AACjB,OAAO,oBAAoB,MAAM,yCAAyC,CAAC;AAC3E,OAAO,kBAAkB,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,YAAY,MAAM,oCAAoC,CAAC;AAE9D,OAAO,sBAAsB,MAAM,2CAA2C,CAAC;
|
|
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"}
|