@sudobility/entity_service 1.0.4 → 1.0.6
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/helpers/EntityHelper.cjs +29 -21
- package/dist/helpers/EntityHelper.d.ts +12 -4
- package/dist/helpers/EntityHelper.d.ts.map +1 -1
- package/dist/helpers/EntityHelper.js +29 -21
- package/dist/helpers/EntityHelper.js.map +1 -1
- package/dist/helpers/EntityMemberHelper.cjs +86 -47
- package/dist/helpers/EntityMemberHelper.d.ts +11 -3
- package/dist/helpers/EntityMemberHelper.d.ts.map +1 -1
- package/dist/helpers/EntityMemberHelper.js +86 -47
- package/dist/helpers/EntityMemberHelper.js.map +1 -1
- package/dist/helpers/InvitationHelper.cjs +15 -10
- package/dist/helpers/InvitationHelper.d.ts +6 -2
- package/dist/helpers/InvitationHelper.d.ts.map +1 -1
- package/dist/helpers/InvitationHelper.js +15 -10
- package/dist/helpers/InvitationHelper.js.map +1 -1
- package/dist/helpers/PermissionHelper.cjs +8 -12
- package/dist/helpers/PermissionHelper.d.ts +3 -0
- package/dist/helpers/PermissionHelper.d.ts.map +1 -1
- package/dist/helpers/PermissionHelper.js +8 -12
- package/dist/helpers/PermissionHelper.js.map +1 -1
- package/dist/middleware/hono.cjs +6 -6
- package/dist/middleware/hono.d.ts +3 -3
- package/dist/middleware/hono.js +6 -6
- package/dist/middleware/hono.js.map +1 -1
- package/dist/migrations/001_add_entities.cjs +93 -32
- package/dist/migrations/001_add_entities.d.ts.map +1 -1
- package/dist/migrations/001_add_entities.js +93 -32
- package/dist/migrations/001_add_entities.js.map +1 -1
- package/dist/schema/entities.cjs +30 -23
- package/dist/schema/entities.d.ts +61 -46
- package/dist/schema/entities.d.ts.map +1 -1
- package/dist/schema/entities.js +30 -23
- package/dist/schema/entities.js.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -18,8 +18,10 @@ class EntityHelper {
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a personal entity for a user.
|
|
20
20
|
* Called automatically when a user first logs in.
|
|
21
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
22
|
+
* @param email - Optional email for display name
|
|
21
23
|
*/
|
|
22
|
-
async createPersonalEntity(
|
|
24
|
+
async createPersonalEntity(firebaseUid, email) {
|
|
23
25
|
const slug = (0, utils_1.generateEntitySlug)();
|
|
24
26
|
const displayName = email?.split('@')[0] ?? 'Personal';
|
|
25
27
|
const [entity] = await this.config.db
|
|
@@ -28,37 +30,42 @@ class EntityHelper {
|
|
|
28
30
|
entity_slug: slug,
|
|
29
31
|
entity_type: types_1.EntityType.PERSONAL,
|
|
30
32
|
display_name: displayName,
|
|
31
|
-
owner_user_id: userId,
|
|
32
33
|
})
|
|
33
34
|
.returning();
|
|
34
|
-
// Add user as admin
|
|
35
|
+
// Add user as admin (personal entities use admin role, not owner)
|
|
35
36
|
await this.config.db.insert(this.config.membersTable).values({
|
|
36
37
|
entity_id: entity.id,
|
|
37
|
-
user_id:
|
|
38
|
+
user_id: firebaseUid,
|
|
38
39
|
role: types_1.EntityRole.ADMIN,
|
|
40
|
+
is_active: true,
|
|
39
41
|
});
|
|
40
42
|
return this.mapRecordToEntity(entity);
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Get or create a personal entity for a user.
|
|
44
46
|
* Ensures exactly one personal entity exists per user.
|
|
47
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
48
|
+
* @param email - Optional email for display name
|
|
45
49
|
*/
|
|
46
|
-
async getOrCreatePersonalEntity(
|
|
47
|
-
// Check for existing personal entity
|
|
50
|
+
async getOrCreatePersonalEntity(firebaseUid, email) {
|
|
51
|
+
// Check for existing personal entity where user is admin
|
|
48
52
|
const existing = await this.config.db
|
|
49
|
-
.select()
|
|
50
|
-
.from(this.config.
|
|
51
|
-
.
|
|
53
|
+
.select({ entity: this.config.entitiesTable })
|
|
54
|
+
.from(this.config.membersTable)
|
|
55
|
+
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
56
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true), (0, drizzle_orm_1.eq)(this.config.entitiesTable.entity_type, types_1.EntityType.PERSONAL)))
|
|
52
57
|
.limit(1);
|
|
53
58
|
if (existing.length > 0) {
|
|
54
|
-
return this.mapRecordToEntity(existing[0]);
|
|
59
|
+
return this.mapRecordToEntity(existing[0].entity);
|
|
55
60
|
}
|
|
56
|
-
return this.createPersonalEntity(
|
|
61
|
+
return this.createPersonalEntity(firebaseUid, email);
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Create an organization entity.
|
|
65
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
66
|
+
* @param request - Entity creation request
|
|
60
67
|
*/
|
|
61
|
-
async createOrganizationEntity(
|
|
68
|
+
async createOrganizationEntity(firebaseUid, request) {
|
|
62
69
|
// Determine slug
|
|
63
70
|
let slug;
|
|
64
71
|
if (request.entitySlug) {
|
|
@@ -81,14 +88,14 @@ class EntityHelper {
|
|
|
81
88
|
entity_type: types_1.EntityType.ORGANIZATION,
|
|
82
89
|
display_name: request.displayName,
|
|
83
90
|
description: request.description ?? null,
|
|
84
|
-
owner_user_id: userId,
|
|
85
91
|
})
|
|
86
92
|
.returning();
|
|
87
|
-
// Add creator as
|
|
93
|
+
// Add creator as owner
|
|
88
94
|
await this.config.db.insert(this.config.membersTable).values({
|
|
89
95
|
entity_id: entity.id,
|
|
90
|
-
user_id:
|
|
91
|
-
role: types_1.EntityRole.
|
|
96
|
+
user_id: firebaseUid,
|
|
97
|
+
role: types_1.EntityRole.OWNER,
|
|
98
|
+
is_active: true,
|
|
92
99
|
});
|
|
93
100
|
return this.mapRecordToEntity(entity);
|
|
94
101
|
}
|
|
@@ -123,8 +130,10 @@ class EntityHelper {
|
|
|
123
130
|
/**
|
|
124
131
|
* Get all entities a user is a member of.
|
|
125
132
|
* If the user has no entities, a personal entity is automatically created.
|
|
133
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
134
|
+
* @param email - Optional email for display name if creating personal entity
|
|
126
135
|
*/
|
|
127
|
-
async getUserEntities(
|
|
136
|
+
async getUserEntities(firebaseUid, email) {
|
|
128
137
|
const results = await this.config.db
|
|
129
138
|
.select({
|
|
130
139
|
entity: this.config.entitiesTable,
|
|
@@ -132,14 +141,14 @@ class EntityHelper {
|
|
|
132
141
|
})
|
|
133
142
|
.from(this.config.membersTable)
|
|
134
143
|
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
135
|
-
.where((0, drizzle_orm_1.eq)(this.config.membersTable.user_id,
|
|
144
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)));
|
|
136
145
|
// If user has no entities, create a personal entity for them
|
|
137
146
|
if (results.length === 0) {
|
|
138
|
-
const personalEntity = await this.createPersonalEntity(
|
|
147
|
+
const personalEntity = await this.createPersonalEntity(firebaseUid, email);
|
|
139
148
|
return [
|
|
140
149
|
{
|
|
141
150
|
...personalEntity,
|
|
142
|
-
userRole: types_1.EntityRole.
|
|
151
|
+
userRole: types_1.EntityRole.OWNER,
|
|
143
152
|
},
|
|
144
153
|
];
|
|
145
154
|
}
|
|
@@ -235,7 +244,6 @@ class EntityHelper {
|
|
|
235
244
|
displayName: record.display_name,
|
|
236
245
|
description: record.description,
|
|
237
246
|
avatarUrl: record.avatar_url,
|
|
238
|
-
ownerUserId: record.owner_user_id,
|
|
239
247
|
createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
|
|
240
248
|
updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
|
|
241
249
|
};
|
|
@@ -12,17 +12,23 @@ export declare class EntityHelper {
|
|
|
12
12
|
/**
|
|
13
13
|
* Create a personal entity for a user.
|
|
14
14
|
* Called automatically when a user first logs in.
|
|
15
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
16
|
+
* @param email - Optional email for display name
|
|
15
17
|
*/
|
|
16
|
-
createPersonalEntity(
|
|
18
|
+
createPersonalEntity(firebaseUid: string, email?: string): Promise<Entity>;
|
|
17
19
|
/**
|
|
18
20
|
* Get or create a personal entity for a user.
|
|
19
21
|
* Ensures exactly one personal entity exists per user.
|
|
22
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
23
|
+
* @param email - Optional email for display name
|
|
20
24
|
*/
|
|
21
|
-
getOrCreatePersonalEntity(
|
|
25
|
+
getOrCreatePersonalEntity(firebaseUid: string, email?: string): Promise<Entity>;
|
|
22
26
|
/**
|
|
23
27
|
* Create an organization entity.
|
|
28
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
29
|
+
* @param request - Entity creation request
|
|
24
30
|
*/
|
|
25
|
-
createOrganizationEntity(
|
|
31
|
+
createOrganizationEntity(firebaseUid: string, request: CreateEntityRequest): Promise<Entity>;
|
|
26
32
|
/**
|
|
27
33
|
* Get entity by ID.
|
|
28
34
|
*/
|
|
@@ -34,8 +40,10 @@ export declare class EntityHelper {
|
|
|
34
40
|
/**
|
|
35
41
|
* Get all entities a user is a member of.
|
|
36
42
|
* If the user has no entities, a personal entity is automatically created.
|
|
43
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
44
|
+
* @param email - Optional email for display name if creating personal entity
|
|
37
45
|
*/
|
|
38
|
-
getUserEntities(
|
|
46
|
+
getUserEntities(firebaseUid: string, email?: string): Promise<EntityWithRole[]>;
|
|
39
47
|
/**
|
|
40
48
|
* Update entity details.
|
|
41
49
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAGlB;;GAEG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD
|
|
1
|
+
{"version":3,"file":"EntityHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAGlB;;GAEG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD;;;;;OAKG;IACG,oBAAoB,CACxB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAwBlB;;;;;OAKG;IACG,yBAAyB,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IA0BlB;;;;OAIG;IACG,wBAAwB,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC;IAqClB;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAczD;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAc3D;;;;;OAKG;IACG,eAAe,CACnB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,EAAE,CAAC;IAmC5B;;OAEG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC;IAyClB;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAenD;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrD;;OAEG;YACW,kBAAkB;IAUhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAY1B"}
|
|
@@ -18,8 +18,10 @@ class EntityHelper {
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a personal entity for a user.
|
|
20
20
|
* Called automatically when a user first logs in.
|
|
21
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
22
|
+
* @param email - Optional email for display name
|
|
21
23
|
*/
|
|
22
|
-
async createPersonalEntity(
|
|
24
|
+
async createPersonalEntity(firebaseUid, email) {
|
|
23
25
|
const slug = (0, utils_1.generateEntitySlug)();
|
|
24
26
|
const displayName = email?.split('@')[0] ?? 'Personal';
|
|
25
27
|
const [entity] = await this.config.db
|
|
@@ -28,37 +30,42 @@ class EntityHelper {
|
|
|
28
30
|
entity_slug: slug,
|
|
29
31
|
entity_type: types_1.EntityType.PERSONAL,
|
|
30
32
|
display_name: displayName,
|
|
31
|
-
owner_user_id: userId,
|
|
32
33
|
})
|
|
33
34
|
.returning();
|
|
34
|
-
// Add user as admin
|
|
35
|
+
// Add user as admin (personal entities use admin role, not owner)
|
|
35
36
|
await this.config.db.insert(this.config.membersTable).values({
|
|
36
37
|
entity_id: entity.id,
|
|
37
|
-
user_id:
|
|
38
|
+
user_id: firebaseUid,
|
|
38
39
|
role: types_1.EntityRole.ADMIN,
|
|
40
|
+
is_active: true,
|
|
39
41
|
});
|
|
40
42
|
return this.mapRecordToEntity(entity);
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
43
45
|
* Get or create a personal entity for a user.
|
|
44
46
|
* Ensures exactly one personal entity exists per user.
|
|
47
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
48
|
+
* @param email - Optional email for display name
|
|
45
49
|
*/
|
|
46
|
-
async getOrCreatePersonalEntity(
|
|
47
|
-
// Check for existing personal entity
|
|
50
|
+
async getOrCreatePersonalEntity(firebaseUid, email) {
|
|
51
|
+
// Check for existing personal entity where user is admin
|
|
48
52
|
const existing = await this.config.db
|
|
49
|
-
.select()
|
|
50
|
-
.from(this.config.
|
|
51
|
-
.
|
|
53
|
+
.select({ entity: this.config.entitiesTable })
|
|
54
|
+
.from(this.config.membersTable)
|
|
55
|
+
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
56
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true), (0, drizzle_orm_1.eq)(this.config.entitiesTable.entity_type, types_1.EntityType.PERSONAL)))
|
|
52
57
|
.limit(1);
|
|
53
58
|
if (existing.length > 0) {
|
|
54
|
-
return this.mapRecordToEntity(existing[0]);
|
|
59
|
+
return this.mapRecordToEntity(existing[0].entity);
|
|
55
60
|
}
|
|
56
|
-
return this.createPersonalEntity(
|
|
61
|
+
return this.createPersonalEntity(firebaseUid, email);
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Create an organization entity.
|
|
65
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
66
|
+
* @param request - Entity creation request
|
|
60
67
|
*/
|
|
61
|
-
async createOrganizationEntity(
|
|
68
|
+
async createOrganizationEntity(firebaseUid, request) {
|
|
62
69
|
// Determine slug
|
|
63
70
|
let slug;
|
|
64
71
|
if (request.entitySlug) {
|
|
@@ -81,14 +88,14 @@ class EntityHelper {
|
|
|
81
88
|
entity_type: types_1.EntityType.ORGANIZATION,
|
|
82
89
|
display_name: request.displayName,
|
|
83
90
|
description: request.description ?? null,
|
|
84
|
-
owner_user_id: userId,
|
|
85
91
|
})
|
|
86
92
|
.returning();
|
|
87
|
-
// Add creator as
|
|
93
|
+
// Add creator as owner
|
|
88
94
|
await this.config.db.insert(this.config.membersTable).values({
|
|
89
95
|
entity_id: entity.id,
|
|
90
|
-
user_id:
|
|
91
|
-
role: types_1.EntityRole.
|
|
96
|
+
user_id: firebaseUid,
|
|
97
|
+
role: types_1.EntityRole.OWNER,
|
|
98
|
+
is_active: true,
|
|
92
99
|
});
|
|
93
100
|
return this.mapRecordToEntity(entity);
|
|
94
101
|
}
|
|
@@ -123,8 +130,10 @@ class EntityHelper {
|
|
|
123
130
|
/**
|
|
124
131
|
* Get all entities a user is a member of.
|
|
125
132
|
* If the user has no entities, a personal entity is automatically created.
|
|
133
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
134
|
+
* @param email - Optional email for display name if creating personal entity
|
|
126
135
|
*/
|
|
127
|
-
async getUserEntities(
|
|
136
|
+
async getUserEntities(firebaseUid, email) {
|
|
128
137
|
const results = await this.config.db
|
|
129
138
|
.select({
|
|
130
139
|
entity: this.config.entitiesTable,
|
|
@@ -132,14 +141,14 @@ class EntityHelper {
|
|
|
132
141
|
})
|
|
133
142
|
.from(this.config.membersTable)
|
|
134
143
|
.innerJoin(this.config.entitiesTable, (0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, this.config.entitiesTable.id))
|
|
135
|
-
.where((0, drizzle_orm_1.eq)(this.config.membersTable.user_id,
|
|
144
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)));
|
|
136
145
|
// If user has no entities, create a personal entity for them
|
|
137
146
|
if (results.length === 0) {
|
|
138
|
-
const personalEntity = await this.createPersonalEntity(
|
|
147
|
+
const personalEntity = await this.createPersonalEntity(firebaseUid, email);
|
|
139
148
|
return [
|
|
140
149
|
{
|
|
141
150
|
...personalEntity,
|
|
142
|
-
userRole: types_1.EntityRole.
|
|
151
|
+
userRole: types_1.EntityRole.OWNER,
|
|
143
152
|
},
|
|
144
153
|
];
|
|
145
154
|
}
|
|
@@ -235,7 +244,6 @@ class EntityHelper {
|
|
|
235
244
|
displayName: record.display_name,
|
|
236
245
|
description: record.description,
|
|
237
246
|
avatarUrl: record.avatar_url,
|
|
238
|
-
ownerUserId: record.owner_user_id,
|
|
239
247
|
createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
|
|
240
248
|
updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
|
|
241
249
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityHelper.js","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAAsC;AACtC,oCAQkB;AAClB,oCAA2E;AAE3E;;GAEG;AACH,MAAa,YAAY;IACvB,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D
|
|
1
|
+
{"version":3,"file":"EntityHelper.js","sourceRoot":"","sources":["../../src/helpers/EntityHelper.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,24 +16,28 @@ class EntityMemberHelper {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Get all members of an entity.
|
|
19
|
+
* By default, only returns active members.
|
|
19
20
|
*/
|
|
20
21
|
async getMembers(entityId, options) {
|
|
21
|
-
// Build conditions
|
|
22
|
+
// Build conditions - default to active members only
|
|
22
23
|
const conditions = [(0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId)];
|
|
23
24
|
if (options?.role) {
|
|
24
25
|
conditions.push((0, drizzle_orm_1.eq)(this.config.membersTable.role, options.role));
|
|
25
26
|
}
|
|
27
|
+
// Filter by is_active (default to true if not specified)
|
|
28
|
+
const isActive = options?.isActive ?? true;
|
|
29
|
+
conditions.push((0, drizzle_orm_1.eq)(this.config.membersTable.is_active, isActive));
|
|
26
30
|
let query = this.config.db
|
|
27
31
|
.select({
|
|
28
32
|
member: this.config.membersTable,
|
|
29
33
|
user: {
|
|
30
|
-
id: this.config.usersTable.
|
|
34
|
+
id: this.config.usersTable.firebase_uid,
|
|
31
35
|
email: this.config.usersTable.email,
|
|
32
36
|
displayName: this.config.usersTable.display_name,
|
|
33
37
|
},
|
|
34
38
|
})
|
|
35
39
|
.from(this.config.membersTable)
|
|
36
|
-
.leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.
|
|
40
|
+
.leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.firebase_uid))
|
|
37
41
|
.where((0, drizzle_orm_1.and)(...conditions))
|
|
38
42
|
.$dynamic();
|
|
39
43
|
if (options?.limit) {
|
|
@@ -47,20 +51,28 @@ class EntityMemberHelper {
|
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Get a specific member by user ID.
|
|
54
|
+
* Only returns active members by default.
|
|
50
55
|
*/
|
|
51
|
-
async getMember(entityId, userId) {
|
|
56
|
+
async getMember(entityId, userId, includeInactive = false) {
|
|
57
|
+
const conditions = [
|
|
58
|
+
(0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId),
|
|
59
|
+
(0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId),
|
|
60
|
+
];
|
|
61
|
+
if (!includeInactive) {
|
|
62
|
+
conditions.push((0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true));
|
|
63
|
+
}
|
|
52
64
|
const results = await this.config.db
|
|
53
65
|
.select({
|
|
54
66
|
member: this.config.membersTable,
|
|
55
67
|
user: {
|
|
56
|
-
id: this.config.usersTable.
|
|
68
|
+
id: this.config.usersTable.firebase_uid,
|
|
57
69
|
email: this.config.usersTable.email,
|
|
58
70
|
displayName: this.config.usersTable.display_name,
|
|
59
71
|
},
|
|
60
72
|
})
|
|
61
73
|
.from(this.config.membersTable)
|
|
62
|
-
.leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.
|
|
63
|
-
.where((0, drizzle_orm_1.and)(
|
|
74
|
+
.leftJoin(this.config.usersTable, (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, this.config.usersTable.firebase_uid))
|
|
75
|
+
.where((0, drizzle_orm_1.and)(...conditions))
|
|
64
76
|
.limit(1);
|
|
65
77
|
if (results.length === 0) {
|
|
66
78
|
return null;
|
|
@@ -69,12 +81,13 @@ class EntityMemberHelper {
|
|
|
69
81
|
}
|
|
70
82
|
/**
|
|
71
83
|
* Get user's role in an entity.
|
|
84
|
+
* Only returns role for active members.
|
|
72
85
|
*/
|
|
73
86
|
async getUserRole(entityId, userId) {
|
|
74
87
|
const results = await this.config.db
|
|
75
88
|
.select({ role: this.config.membersTable.role })
|
|
76
89
|
.from(this.config.membersTable)
|
|
77
|
-
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
|
|
90
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)))
|
|
78
91
|
.limit(1);
|
|
79
92
|
if (results.length === 0) {
|
|
80
93
|
return null;
|
|
@@ -83,32 +96,61 @@ class EntityMemberHelper {
|
|
|
83
96
|
}
|
|
84
97
|
/**
|
|
85
98
|
* Add a member to an entity.
|
|
99
|
+
* @param entityId - The entity ID
|
|
100
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
101
|
+
* @param role - The member's role
|
|
86
102
|
*/
|
|
87
|
-
async addMember(entityId,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
async addMember(entityId, firebaseUid, role) {
|
|
104
|
+
// Check if there's an existing inactive membership to reactivate
|
|
105
|
+
const existing = await this.getMember(entityId, firebaseUid, true);
|
|
106
|
+
let member;
|
|
107
|
+
if (existing && !existing.isActive) {
|
|
108
|
+
// Reactivate existing membership
|
|
109
|
+
const [updated] = await this.config.db
|
|
110
|
+
.update(this.config.membersTable)
|
|
111
|
+
.set({
|
|
112
|
+
role,
|
|
113
|
+
is_active: true,
|
|
114
|
+
updated_at: new Date(),
|
|
115
|
+
})
|
|
116
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, firebaseUid)))
|
|
117
|
+
.returning();
|
|
118
|
+
member = updated;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Create new membership
|
|
122
|
+
const [inserted] = await this.config.db
|
|
123
|
+
.insert(this.config.membersTable)
|
|
124
|
+
.values({
|
|
125
|
+
entity_id: entityId,
|
|
126
|
+
user_id: firebaseUid,
|
|
127
|
+
role,
|
|
128
|
+
is_active: true,
|
|
129
|
+
})
|
|
130
|
+
.returning();
|
|
131
|
+
member = inserted;
|
|
132
|
+
}
|
|
96
133
|
// Fetch user info for response
|
|
97
134
|
const users = await this.config.db
|
|
98
135
|
.select({
|
|
99
|
-
id: this.config.usersTable.
|
|
136
|
+
id: this.config.usersTable.firebase_uid,
|
|
100
137
|
email: this.config.usersTable.email,
|
|
101
138
|
displayName: this.config.usersTable.display_name,
|
|
102
139
|
})
|
|
103
140
|
.from(this.config.usersTable)
|
|
104
|
-
.where((0, drizzle_orm_1.eq)(this.config.usersTable.
|
|
141
|
+
.where((0, drizzle_orm_1.eq)(this.config.usersTable.firebase_uid, firebaseUid))
|
|
105
142
|
.limit(1);
|
|
106
143
|
return this.mapRecordToMember(member, users[0] ?? null);
|
|
107
144
|
}
|
|
108
145
|
/**
|
|
109
146
|
* Update a member's role.
|
|
147
|
+
* Cannot change the owner's role. Cannot set anyone to owner (ownership transfer is separate).
|
|
110
148
|
*/
|
|
111
149
|
async updateMemberRole(entityId, userId, role) {
|
|
150
|
+
// Cannot assign owner role via this method
|
|
151
|
+
if (role === types_1.EntityRole.OWNER) {
|
|
152
|
+
throw new Error('Cannot assign owner role. Use ownership transfer instead.');
|
|
153
|
+
}
|
|
112
154
|
// Check constraints for personal entities
|
|
113
155
|
const entity = await this.config.db
|
|
114
156
|
.select()
|
|
@@ -118,16 +160,10 @@ class EntityMemberHelper {
|
|
|
118
160
|
if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
|
|
119
161
|
throw new Error('Cannot change roles in personal entities');
|
|
120
162
|
}
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.from(this.config.membersTable)
|
|
126
|
-
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.role, types_1.EntityRole.ADMIN)));
|
|
127
|
-
const isOnlyAdmin = admins.length === 1 && admins[0].user_id === userId;
|
|
128
|
-
if (isOnlyAdmin) {
|
|
129
|
-
throw new Error('Cannot demote the only admin');
|
|
130
|
-
}
|
|
163
|
+
// Check if user is the owner - cannot change owner's role
|
|
164
|
+
const currentMember = await this.getMember(entityId, userId);
|
|
165
|
+
if (currentMember?.role === types_1.EntityRole.OWNER) {
|
|
166
|
+
throw new Error('Cannot change the owner\'s role');
|
|
131
167
|
}
|
|
132
168
|
const [updated] = await this.config.db
|
|
133
169
|
.update(this.config.membersTable)
|
|
@@ -135,22 +171,26 @@ class EntityMemberHelper {
|
|
|
135
171
|
role,
|
|
136
172
|
updated_at: new Date(),
|
|
137
173
|
})
|
|
138
|
-
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)))
|
|
174
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId), (0, drizzle_orm_1.eq)(this.config.membersTable.is_active, true)))
|
|
139
175
|
.returning();
|
|
176
|
+
if (!updated) {
|
|
177
|
+
throw new Error('Member not found or inactive');
|
|
178
|
+
}
|
|
140
179
|
// Fetch user info for response
|
|
141
180
|
const users = await this.config.db
|
|
142
181
|
.select({
|
|
143
|
-
id: this.config.usersTable.
|
|
182
|
+
id: this.config.usersTable.firebase_uid,
|
|
144
183
|
email: this.config.usersTable.email,
|
|
145
184
|
displayName: this.config.usersTable.display_name,
|
|
146
185
|
})
|
|
147
186
|
.from(this.config.usersTable)
|
|
148
|
-
.where((0, drizzle_orm_1.eq)(this.config.usersTable.
|
|
187
|
+
.where((0, drizzle_orm_1.eq)(this.config.usersTable.firebase_uid, userId))
|
|
149
188
|
.limit(1);
|
|
150
189
|
return this.mapRecordToMember(updated, users[0] ?? null);
|
|
151
190
|
}
|
|
152
191
|
/**
|
|
153
|
-
* Remove a member from an entity.
|
|
192
|
+
* Remove a member from an entity (soft delete).
|
|
193
|
+
* Sets is_active = false instead of deleting the record.
|
|
154
194
|
*/
|
|
155
195
|
async removeMember(entityId, userId) {
|
|
156
196
|
// Check constraints for personal entities
|
|
@@ -162,23 +202,21 @@ class EntityMemberHelper {
|
|
|
162
202
|
if (entity.length > 0 && entity[0].entity_type === types_1.EntityType.PERSONAL) {
|
|
163
203
|
throw new Error('Cannot remove members from personal entities');
|
|
164
204
|
}
|
|
165
|
-
// Check if user is the owner
|
|
166
|
-
if (entity.length > 0 && entity[0].owner_user_id === userId) {
|
|
167
|
-
throw new Error('Cannot remove the entity owner');
|
|
168
|
-
}
|
|
169
|
-
// Ensure at least one admin remains
|
|
205
|
+
// Check if user is the owner - cannot remove owner
|
|
170
206
|
const member = await this.getMember(entityId, userId);
|
|
171
|
-
if (member
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (admins.length === 1) {
|
|
177
|
-
throw new Error('Cannot remove the only admin');
|
|
178
|
-
}
|
|
207
|
+
if (!member) {
|
|
208
|
+
throw new Error('Member not found');
|
|
209
|
+
}
|
|
210
|
+
if (member.role === types_1.EntityRole.OWNER) {
|
|
211
|
+
throw new Error('Cannot remove the entity owner');
|
|
179
212
|
}
|
|
213
|
+
// Soft delete - set is_active = false
|
|
180
214
|
await this.config.db
|
|
181
|
-
.
|
|
215
|
+
.update(this.config.membersTable)
|
|
216
|
+
.set({
|
|
217
|
+
is_active: false,
|
|
218
|
+
updated_at: new Date(),
|
|
219
|
+
})
|
|
182
220
|
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.config.membersTable.entity_id, entityId), (0, drizzle_orm_1.eq)(this.config.membersTable.user_id, userId)));
|
|
183
221
|
}
|
|
184
222
|
/**
|
|
@@ -197,6 +235,7 @@ class EntityMemberHelper {
|
|
|
197
235
|
entityId: record.entity_id,
|
|
198
236
|
userId: record.user_id,
|
|
199
237
|
role: record.role,
|
|
238
|
+
isActive: record.is_active ?? true,
|
|
200
239
|
joinedAt: record.joined_at?.toISOString() ?? new Date().toISOString(),
|
|
201
240
|
createdAt: record.created_at?.toISOString() ?? new Date().toISOString(),
|
|
202
241
|
updatedAt: record.updated_at?.toISOString() ?? new Date().toISOString(),
|
|
@@ -11,26 +11,34 @@ export declare class EntityMemberHelper {
|
|
|
11
11
|
constructor(config: EntityHelperConfig);
|
|
12
12
|
/**
|
|
13
13
|
* Get all members of an entity.
|
|
14
|
+
* By default, only returns active members.
|
|
14
15
|
*/
|
|
15
16
|
getMembers(entityId: string, options?: ListMembersOptions): Promise<EntityMember[]>;
|
|
16
17
|
/**
|
|
17
18
|
* Get a specific member by user ID.
|
|
19
|
+
* Only returns active members by default.
|
|
18
20
|
*/
|
|
19
|
-
getMember(entityId: string, userId: string): Promise<EntityMember | null>;
|
|
21
|
+
getMember(entityId: string, userId: string, includeInactive?: boolean): Promise<EntityMember | null>;
|
|
20
22
|
/**
|
|
21
23
|
* Get user's role in an entity.
|
|
24
|
+
* Only returns role for active members.
|
|
22
25
|
*/
|
|
23
26
|
getUserRole(entityId: string, userId: string): Promise<EntityRole | null>;
|
|
24
27
|
/**
|
|
25
28
|
* Add a member to an entity.
|
|
29
|
+
* @param entityId - The entity ID
|
|
30
|
+
* @param firebaseUid - The Firebase UID (used as user_id)
|
|
31
|
+
* @param role - The member's role
|
|
26
32
|
*/
|
|
27
|
-
addMember(entityId: string,
|
|
33
|
+
addMember(entityId: string, firebaseUid: string, role: EntityRole): Promise<EntityMember>;
|
|
28
34
|
/**
|
|
29
35
|
* Update a member's role.
|
|
36
|
+
* Cannot change the owner's role. Cannot set anyone to owner (ownership transfer is separate).
|
|
30
37
|
*/
|
|
31
38
|
updateMemberRole(entityId: string, userId: string, role: EntityRole): Promise<EntityMember>;
|
|
32
39
|
/**
|
|
33
|
-
* Remove a member from an entity.
|
|
40
|
+
* Remove a member from an entity (soft delete).
|
|
41
|
+
* Sets is_active = false instead of deleting the record.
|
|
34
42
|
*/
|
|
35
43
|
removeMember(entityId: string, userId: string): Promise<void>;
|
|
36
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityMemberHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityMemberHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,UAAU,EAEV,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD
|
|
1
|
+
{"version":3,"file":"EntityMemberHelper.d.ts","sourceRoot":"","sources":["../../src/helpers/EntityMemberHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,UAAU,EAEV,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,kBAAkB;IAEvD;;;OAGG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,EAAE,CAAC;IA0C1B;;;OAGG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,eAAe,UAAQ,GACtB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAiC/B;;;OAGG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAoB7B;;;;;OAKG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC;IAkDxB;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC;IAwDxB;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCnE;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAyB1B"}
|