@tmlmobilidade/interfaces 20251006.1651.45 → 20251007.946.5-staging.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/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './src/aggregation-pipeline.js';
2
- export * from './src/enrich-user-refs.js';
3
2
  export * from './src/interfaces/index.js';
4
3
  export * from './src/mongo-collection.js';
5
4
  export * from './src/mongo-transaction.js';
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  /* * */
2
2
  export * from './src/aggregation-pipeline.js';
3
- export * from './src/enrich-user-refs.js';
4
3
  export * from './src/interfaces/index.js';
5
4
  export * from './src/mongo-collection.js';
6
5
  export * from './src/mongo-transaction.js';
@@ -2,6 +2,7 @@ import { MongoCollectionClass } from '../../mongo-collection.js';
2
2
  import { CreateUserDto, UpdateUserDto, User } from '@tmlmobilidade/types';
3
3
  import { Filter, FindOptions, IndexDescription, WithId } from 'mongodb';
4
4
  import { z } from 'zod';
5
+ type NewType = string;
5
6
  declare class UsersClass extends MongoCollectionClass<User, CreateUserDto, UpdateUserDto> {
6
7
  private static _instance;
7
8
  protected createSchema: z.ZodSchema;
@@ -31,7 +32,7 @@ declare class UsersClass extends MongoCollectionClass<User, CreateUserDto, Updat
31
32
  * @param includePasswordHash - Whether to include the password hash in the result
32
33
  * @returns A promise that resolves to the matching user documents or null if not found
33
34
  */
34
- findByOrganization(id: string, includePasswordHash?: boolean): Promise<{
35
+ findByOrganization(id: NewType, includePasswordHash?: boolean): Promise<{
35
36
  created_at: number & {
36
37
  __brand: "UnixTimestamp";
37
38
  };
@@ -40,15 +41,15 @@ declare class UsersClass extends MongoCollectionClass<User, CreateUserDto, Updat
40
41
  };
41
42
  created_by?: string | undefined | undefined;
42
43
  updated_by?: string | undefined | undefined;
44
+ phone?: string | null | undefined | undefined;
45
+ email: string;
46
+ permissions: import("@tmlmobilidade/types").Permission<unknown>[];
43
47
  avatar?: string | null | undefined | undefined;
44
48
  bio?: string | null | undefined | undefined;
45
- email: string;
46
49
  email_verified?: import("@tmlmobilidade/types").UnixTimestamp | null | undefined;
47
50
  first_name: string;
48
51
  last_name: string;
49
52
  organization_id?: string | null | undefined | undefined;
50
- permissions: import("@tmlmobilidade/types").Permission<unknown>[];
51
- phone?: string | null | undefined | undefined;
52
53
  preferences?: Record<string, Record<string, string | number | boolean | string[] | number[]>> | null | undefined;
53
54
  role_ids: string[];
54
55
  session_ids: string[];
@@ -71,15 +72,15 @@ declare class UsersClass extends MongoCollectionClass<User, CreateUserDto, Updat
71
72
  };
72
73
  created_by?: string | undefined | undefined;
73
74
  updated_by?: string | undefined | undefined;
75
+ phone?: string | null | undefined | undefined;
76
+ email: string;
77
+ permissions: import("@tmlmobilidade/types").Permission<unknown>[];
74
78
  avatar?: string | null | undefined | undefined;
75
79
  bio?: string | null | undefined | undefined;
76
- email: string;
77
80
  email_verified?: import("@tmlmobilidade/types").UnixTimestamp | null | undefined;
78
81
  first_name: string;
79
82
  last_name: string;
80
83
  organization_id?: string | null | undefined | undefined;
81
- permissions: import("@tmlmobilidade/types").Permission<unknown>[];
82
- phone?: string | null | undefined | undefined;
83
84
  preferences?: Record<string, Record<string, string | number | boolean | string[] | number[]>> | null | undefined;
84
85
  role_ids: string[];
85
86
  session_ids: string[];
@@ -2,7 +2,6 @@
2
2
  import { MongoCollectionClass } from '../../mongo-collection.js';
3
3
  import { UpdateUserSchema, UserSchema } from '@tmlmobilidade/types';
4
4
  import { AsyncSingletonProxy } from '@tmlmobilidade/utils';
5
- /* * */
6
5
  class UsersClass extends MongoCollectionClass {
7
6
  static _instance;
8
7
  createSchema = UserSchema;
@@ -1,5 +1,5 @@
1
1
  import { MongoCollectionClass } from '../../mongo-collection.js';
2
- import { CreateNotificationDto, Notification, UpdateNotificationDto } from '@tmlmobilidade/types';
2
+ import { CreateNotificationDto, Notification, UpdateNotificationDto, User } from '@tmlmobilidade/types';
3
3
  import { IndexDescription } from 'mongodb';
4
4
  import { z } from 'zod';
5
5
  declare class NotificationsClass extends MongoCollectionClass<Notification, CreateNotificationDto, UpdateNotificationDto> {
@@ -8,7 +8,7 @@ declare class NotificationsClass extends MongoCollectionClass<Notification, Crea
8
8
  protected updateSchema: z.ZodSchema;
9
9
  private constructor();
10
10
  static getInstance(): Promise<NotificationsClass>;
11
- sendNotification(notification: CreateNotificationDto): Promise<void>;
11
+ sendNotification(scope: string, topic: string, user: User, id: string, title: string, description: string): Promise<void>;
12
12
  protected getCollectionIndexes(): IndexDescription[];
13
13
  protected getCollectionName(): string;
14
14
  protected getCreateSchema(): z.ZodSchema;
@@ -1,5 +1,7 @@
1
1
  /* * */
2
2
  import { MongoCollectionClass } from '../../mongo-collection.js';
3
+ import { sendNotificationEmail } from '@tmlmobilidade/emails';
4
+ import { getAppConfig } from '@tmlmobilidade/lib';
3
5
  import { NotificationSchema, UpdateNotificationSchema } from '@tmlmobilidade/types';
4
6
  import { AsyncSingletonProxy } from '@tmlmobilidade/utils';
5
7
  import { users } from '../auth/users.js';
@@ -19,12 +21,39 @@ class NotificationsClass extends MongoCollectionClass {
19
21
  }
20
22
  return NotificationsClass._instance;
21
23
  }
22
- async sendNotification(notification) {
23
- const usersWithTopic = await users.findMany({ 'permissions.action': notification.topic });
24
+ async sendNotification(scope, topic, user, id, title, description) {
25
+ const usersWithTopic = await users.findMany({ 'permissions.action': topic });
24
26
  if (usersWithTopic.length === 0)
25
27
  return;
28
+ const notification = {
29
+ created_by: user?._id,
30
+ is_read: false,
31
+ payload: {
32
+ body: description,
33
+ href: `${getAppConfig(`${scope}`, 'frontend_url')}/${scope}/${id}`,
34
+ icon: scope,
35
+ title: title,
36
+ },
37
+ priority: 'normal',
38
+ scope: scope,
39
+ topic: topic,
40
+ updated_by: user?._id,
41
+ };
26
42
  for (const user of usersWithTopic.filter(u => u._id !== notification.created_by)) {
43
+ const sendMail = user?.permissions.find(p => p.scope === 'notifications' && p.action === topic)?.resource ?? false;
27
44
  const newNotification = { ...notification, user_id: user._id };
45
+ if (sendMail) {
46
+ await sendNotificationEmail({
47
+ props: {
48
+ body: notification.payload.body,
49
+ href: notification.payload.href || '',
50
+ priority: notification.priority,
51
+ scope: notification.scope,
52
+ title: notification.payload.title,
53
+ topic: notification.topic,
54
+ }, to: user.email,
55
+ });
56
+ }
28
57
  await notifications.insertOne(newNotification);
29
58
  }
30
59
  }
@@ -1,8 +1,8 @@
1
- import { AggregationPipeline } from './aggregation-pipeline.js';
2
1
  import { MongoConnector } from '@tmlmobilidade/connectors';
3
2
  import { type UnixTimestamp } from '@tmlmobilidade/types';
4
3
  import { AggregateOptions, AggregationCursor, Collection, DeleteOptions, DeleteResult, Document, Filter, FindOptions, IndexDescription, InsertManyResult, InsertOneOptions, InsertOneResult, MongoClientOptions, UpdateOptions, UpdateResult, WithId } from 'mongodb';
5
4
  import { z } from 'zod';
5
+ import { AggregationPipeline } from './aggregation-pipeline.js';
6
6
  export declare abstract class MongoCollectionClass<T extends Document, TCreate, TUpdate> {
7
7
  protected createSchema: null | z.ZodSchema;
8
8
  protected mongoCollection: Collection<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/interfaces",
3
- "version": "20251006.1651.45",
3
+ "version": "20251007.946.5-staging.0",
4
4
  "author": "João de Vasconcelos & Jusi Monteiro",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "homepage": "https://github.com/tmlmobilidade/services#readme",
@@ -36,8 +36,8 @@
36
36
  "lint:fix": "eslint --fix"
37
37
  },
38
38
  "dependencies": {
39
- "@aws-sdk/client-s3": "3.901.0",
40
- "@aws-sdk/s3-request-presigner": "3.901.0",
39
+ "@aws-sdk/client-s3": "3.899.0",
40
+ "@aws-sdk/s3-request-presigner": "3.899.0",
41
41
  "@tmlmobilidade/connectors": "*",
42
42
  "@tmlmobilidade/emails": "*",
43
43
  "@tmlmobilidade/lib": "*",
@@ -54,7 +54,7 @@
54
54
  "devDependencies": {
55
55
  "@carrismetropolitana/eslint": "20250622.1204.50",
56
56
  "@types/luxon": "3.7.1",
57
- "@types/node": "24.7.0",
57
+ "@types/node": "24.6.1",
58
58
  "resolve-tspaths": "0.8.23",
59
59
  "rimraf": "6.0.1",
60
60
  "typescript": "5.9.3"
@@ -1,4 +0,0 @@
1
- type AnyDoc = Record<string, any>;
2
- export declare function enrichUserRefs<T extends AnyDoc>(doc: T): Promise<T>;
3
- export declare function enrichUserRefsMany<T extends AnyDoc>(docs: T[]): Promise<T[]>;
4
- export {};
@@ -1,75 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { users } from './interfaces/auth/users.js';
3
- import { UserDisplayFields } from '@tmlmobilidade/types';
4
- const isUserRefKey = (k) => k === 'created_by' || k === 'updated_by';
5
- const isEligibleId = (v) => typeof v === 'string' && v && v !== 'system';
6
- function collectUserIds(input, out) {
7
- if (Array.isArray(input)) {
8
- for (const item of input)
9
- collectUserIds(item, out);
10
- return;
11
- }
12
- if (input && typeof input === 'object') {
13
- for (const [k, v] of Object.entries(input)) {
14
- if (isUserRefKey(k) && isEligibleId(v))
15
- out.add(v);
16
- collectUserIds(v, out);
17
- }
18
- }
19
- }
20
- function replaceRefs(input, map) {
21
- if (Array.isArray(input)) {
22
- return input.map(item => replaceRefs(item, map));
23
- }
24
- if (input && typeof input === 'object') {
25
- const obj = input;
26
- const out = Array.isArray(obj) ? [] : {};
27
- for (const [k, v] of Object.entries(obj)) {
28
- if (isUserRefKey(k) && typeof v === 'string' && v !== 'system') {
29
- const found = map.get(v);
30
- out[k] = found ?? v; // fallback to original id if user not found
31
- }
32
- else {
33
- out[k] = replaceRefs(v, map);
34
- }
35
- }
36
- return out;
37
- }
38
- return input;
39
- }
40
- async function fetchUsersMap(ids) {
41
- if (ids.size === 0)
42
- return new Map();
43
- const coll = await users.getCollection();
44
- // Only fetch UserDisplay fields
45
- const projection = Object.keys(UserDisplayFields).reduce((acc, field) => {
46
- acc[field] = 1;
47
- return acc;
48
- }, {});
49
- const result = await coll.find({ _id: { $in: Array.from(ids) } }, { projection }).toArray();
50
- const map = new Map();
51
- for (const u of result) {
52
- map.set(u._id, {
53
- _id: u._id,
54
- avatar: u.avatar ?? undefined,
55
- email: u.email,
56
- first_name: u.first_name,
57
- last_name: u.last_name,
58
- phone: u.phone ?? undefined,
59
- });
60
- }
61
- return map;
62
- }
63
- export async function enrichUserRefs(doc) {
64
- const ids = new Set();
65
- collectUserIds(doc, ids);
66
- const map = await fetchUsersMap(ids);
67
- return replaceRefs(doc, map);
68
- }
69
- export async function enrichUserRefsMany(docs) {
70
- const ids = new Set();
71
- for (const d of docs)
72
- collectUserIds(d, ids);
73
- const map = await fetchUsersMap(ids);
74
- return docs.map(d => replaceRefs(d, map));
75
- }