@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
|
@@ -16,12 +16,13 @@ class PermissionHelper {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Get a user's role in an entity.
|
|
19
|
+
* Only returns role for active members.
|
|
19
20
|
*/
|
|
20
21
|
async getUserRole(entityId, userId) {
|
|
21
22
|
const results = await this.config.db
|
|
22
23
|
.select({ role: this.config.membersTable.role })
|
|
23
24
|
.from(this.config.membersTable)
|
|
24
|
-
.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)))
|
|
25
|
+
.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)))
|
|
25
26
|
.limit(1);
|
|
26
27
|
if (results.length === 0) {
|
|
27
28
|
return null;
|
|
@@ -53,24 +54,19 @@ class PermissionHelper {
|
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
55
56
|
* Check if user is an admin of an entity.
|
|
57
|
+
* Owner also has admin privileges.
|
|
56
58
|
*/
|
|
57
59
|
async isAdmin(entityId, userId) {
|
|
58
60
|
const role = await this.getUserRole(entityId, userId);
|
|
59
|
-
return role === types_1.EntityRole.ADMIN;
|
|
61
|
+
return role === types_1.EntityRole.ADMIN || role === types_1.EntityRole.OWNER;
|
|
60
62
|
}
|
|
61
63
|
/**
|
|
62
64
|
* Check if user is the owner of an entity.
|
|
65
|
+
* Determined by role = 'owner' in entity_members.
|
|
63
66
|
*/
|
|
64
67
|
async isOwner(entityId, userId) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
.from(this.config.entitiesTable)
|
|
68
|
-
.where((0, drizzle_orm_1.eq)(this.config.entitiesTable.id, entityId))
|
|
69
|
-
.limit(1);
|
|
70
|
-
if (results.length === 0) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
return results[0].ownerUserId === userId;
|
|
68
|
+
const role = await this.getUserRole(entityId, userId);
|
|
69
|
+
return role === types_1.EntityRole.OWNER;
|
|
74
70
|
}
|
|
75
71
|
/**
|
|
76
72
|
* Check if user can view an entity.
|
|
@@ -184,7 +180,7 @@ class PermissionHelper {
|
|
|
184
180
|
*/
|
|
185
181
|
getMinimumRoleForPermission(permission) {
|
|
186
182
|
// Check from lowest to highest privilege
|
|
187
|
-
const roles = [types_1.EntityRole.
|
|
183
|
+
const roles = [types_1.EntityRole.MEMBER, types_1.EntityRole.ADMIN, types_1.EntityRole.OWNER];
|
|
188
184
|
for (const role of roles) {
|
|
189
185
|
if (types_1.ROLE_PERMISSIONS[role][permission]) {
|
|
190
186
|
return role;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionHelper.js","sourceRoot":"","sources":["../../src/helpers/PermissionHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAAsC;AACtC,oCAMkB;AAElB;;GAEG;AACH,MAAa,gBAAgB;IAC3B,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D
|
|
1
|
+
{"version":3,"file":"PermissionHelper.js","sourceRoot":"","sources":["../../src/helpers/PermissionHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6CAAsC;AACtC,oCAMkB;AAElB;;GAEG;AACH,MAAa,gBAAgB;IAC3B,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D;;;OAGG;IACH,KAAK,CAAC,WAAW,CACf,QAAgB,EAChB,MAAc;QAEd,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aACjC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;aAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;aAC9B,KAAK,CACJ,IAAA,iBAAG,EACD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,EAChD,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EAC5C,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAC7C,CACF;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,IAAkB,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,qBAAqB,CAAC,IAAgB;QACpC,OAAO,wBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,QAAgB,EAChB,MAAc;QAEd,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,MAAc;QAC7C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,IAAI,KAAK,IAAI,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,MAAc;QAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,IAAI,KAAK,kBAAU,CAAC,KAAK,IAAI,IAAI,KAAK,kBAAU,CAAC,KAAK,CAAC;IAChE,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,MAAc;QAC5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO,IAAI,KAAK,kBAAU,CAAC,KAAK,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,MAAc;QAClD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,aAAa,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,MAAc;QAClD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,aAAa,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,MAAc;QACpD,4DAA4D;QAC5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAChC,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;aAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;aACjD,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,kBAAU,CAAC,QAAQ,EAAE,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,eAAe,IAAI,KAAK,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,MAAc;QACrD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,gBAAgB,IAAI,KAAK,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,MAAc;QACrD,2DAA2D;QAC3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE;aAChC,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;aAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;aACjD,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,kBAAU,CAAC,QAAQ,EAAE,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,gBAAgB,IAAI,KAAK,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,MAAc;QACtD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,iBAAiB,IAAI,KAAK,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,MAAc;QACtD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,iBAAiB,IAAI,KAAK,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,MAAc;QACpD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,eAAe,IAAI,KAAK,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,MAAc;QACrD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,gBAAgB,IAAI,KAAK,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,MAAc;QACnD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,WAAW,EAAE,cAAc,IAAI,KAAK,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,MAAc,EACd,UAAmC,EACnC,YAAqB;QAErB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEpE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,qCAAqC,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,YAAY,IAAI,0BAA0B,MAAM,CAAC,UAAU,CAAC,EAAE,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,2BAA2B,CACzB,UAAmC;QAEnC,yCAAyC;QACzC,MAAM,KAAK,GAAG,CAAC,kBAAU,CAAC,MAAM,EAAE,kBAAU,CAAC,KAAK,EAAE,kBAAU,CAAC,KAAK,CAAC,CAAC;QAEtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,wBAAgB,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAnOD,4CAmOC"}
|
package/dist/middleware/hono.cjs
CHANGED
|
@@ -103,18 +103,18 @@ function createRequirePermissionMiddleware(permission) {
|
|
|
103
103
|
*
|
|
104
104
|
* Usage:
|
|
105
105
|
* ```typescript
|
|
106
|
-
* const
|
|
106
|
+
* const requireAdmin = createRequireRoleMiddleware(EntityRole.ADMIN);
|
|
107
107
|
*
|
|
108
|
-
* app.post('/api/v1/entities/:entitySlug/projects',
|
|
109
|
-
* // Only
|
|
108
|
+
* app.post('/api/v1/entities/:entitySlug/projects', requireAdmin, (c) => {
|
|
109
|
+
* // Only admins and owners can reach here
|
|
110
110
|
* });
|
|
111
111
|
* ```
|
|
112
112
|
*/
|
|
113
113
|
function createRequireRoleMiddleware(minimumRole) {
|
|
114
114
|
const roleHierarchy = {
|
|
115
|
-
[types_1.EntityRole.
|
|
116
|
-
[types_1.EntityRole.
|
|
117
|
-
[types_1.EntityRole.
|
|
115
|
+
[types_1.EntityRole.MEMBER]: 0,
|
|
116
|
+
[types_1.EntityRole.ADMIN]: 1,
|
|
117
|
+
[types_1.EntityRole.OWNER]: 2,
|
|
118
118
|
};
|
|
119
119
|
return async (c, next) => {
|
|
120
120
|
const userRole = c.get('userRole');
|
|
@@ -64,10 +64,10 @@ export declare function createRequirePermissionMiddleware(permission: keyof Enti
|
|
|
64
64
|
*
|
|
65
65
|
* Usage:
|
|
66
66
|
* ```typescript
|
|
67
|
-
* const
|
|
67
|
+
* const requireAdmin = createRequireRoleMiddleware(EntityRole.ADMIN);
|
|
68
68
|
*
|
|
69
|
-
* app.post('/api/v1/entities/:entitySlug/projects',
|
|
70
|
-
* // Only
|
|
69
|
+
* app.post('/api/v1/entities/:entitySlug/projects', requireAdmin, (c) => {
|
|
70
|
+
* // Only admins and owners can reach here
|
|
71
71
|
* });
|
|
72
72
|
* ```
|
|
73
73
|
*/
|
package/dist/middleware/hono.js
CHANGED
|
@@ -103,18 +103,18 @@ function createRequirePermissionMiddleware(permission) {
|
|
|
103
103
|
*
|
|
104
104
|
* Usage:
|
|
105
105
|
* ```typescript
|
|
106
|
-
* const
|
|
106
|
+
* const requireAdmin = createRequireRoleMiddleware(EntityRole.ADMIN);
|
|
107
107
|
*
|
|
108
|
-
* app.post('/api/v1/entities/:entitySlug/projects',
|
|
109
|
-
* // Only
|
|
108
|
+
* app.post('/api/v1/entities/:entitySlug/projects', requireAdmin, (c) => {
|
|
109
|
+
* // Only admins and owners can reach here
|
|
110
110
|
* });
|
|
111
111
|
* ```
|
|
112
112
|
*/
|
|
113
113
|
function createRequireRoleMiddleware(minimumRole) {
|
|
114
114
|
const roleHierarchy = {
|
|
115
|
-
[types_1.EntityRole.
|
|
116
|
-
[types_1.EntityRole.
|
|
117
|
-
[types_1.EntityRole.
|
|
115
|
+
[types_1.EntityRole.MEMBER]: 0,
|
|
116
|
+
[types_1.EntityRole.ADMIN]: 1,
|
|
117
|
+
[types_1.EntityRole.OWNER]: 2,
|
|
118
118
|
};
|
|
119
119
|
return async (c, next) => {
|
|
120
120
|
const userRole = c.get('userRole');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,10 +35,11 @@ async function runEntityMigration(config) {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Create the entity tables.
|
|
38
|
+
* Note: Ownership is tracked via entity_members (role = 'owner'), not entities.owner_user_id.
|
|
38
39
|
*/
|
|
39
40
|
async function createEntityTables(client, prefix, indexPrefix) {
|
|
40
41
|
console.log('Creating entity tables...');
|
|
41
|
-
// Create entities table
|
|
42
|
+
// Create entities table (ownership tracked via entity_members)
|
|
42
43
|
await client.unsafe(`
|
|
43
44
|
CREATE TABLE IF NOT EXISTS ${prefix}entities (
|
|
44
45
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
@@ -47,7 +48,6 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
47
48
|
display_name VARCHAR(255) NOT NULL,
|
|
48
49
|
description TEXT,
|
|
49
50
|
avatar_url TEXT,
|
|
50
|
-
owner_user_id UUID NOT NULL,
|
|
51
51
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
52
52
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
53
53
|
)
|
|
@@ -55,27 +55,39 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
55
55
|
await client.unsafe(`
|
|
56
56
|
CREATE UNIQUE INDEX IF NOT EXISTS ${indexPrefix}_entities_slug_idx
|
|
57
57
|
ON ${prefix}entities (entity_slug)
|
|
58
|
-
`);
|
|
59
|
-
await client.unsafe(`
|
|
60
|
-
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entities_owner_idx
|
|
61
|
-
ON ${prefix}entities (owner_user_id)
|
|
62
58
|
`);
|
|
63
59
|
await client.unsafe(`
|
|
64
60
|
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entities_type_idx
|
|
65
61
|
ON ${prefix}entities (entity_type)
|
|
66
62
|
`);
|
|
67
|
-
// Create entity_members table
|
|
63
|
+
// Create entity_members table (tracks all user-entity relationships including ownership)
|
|
68
64
|
await client.unsafe(`
|
|
69
65
|
CREATE TABLE IF NOT EXISTS ${prefix}entity_members (
|
|
70
66
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
71
67
|
entity_id UUID NOT NULL REFERENCES ${prefix}entities(id) ON DELETE CASCADE,
|
|
72
|
-
user_id
|
|
73
|
-
role VARCHAR(20) NOT NULL CHECK (role IN ('
|
|
68
|
+
user_id VARCHAR(128) NOT NULL,
|
|
69
|
+
role VARCHAR(20) NOT NULL CHECK (role IN ('owner', 'admin', 'member')),
|
|
70
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
74
71
|
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
|
75
72
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
76
73
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
77
74
|
UNIQUE(entity_id, user_id)
|
|
78
75
|
)
|
|
76
|
+
`);
|
|
77
|
+
// Add is_active column if it doesn't exist (for upgrading existing tables)
|
|
78
|
+
await client.unsafe(`
|
|
79
|
+
DO $$
|
|
80
|
+
BEGIN
|
|
81
|
+
IF NOT EXISTS (
|
|
82
|
+
SELECT 1 FROM information_schema.columns
|
|
83
|
+
WHERE table_schema = '${prefix.replace('.', '')}'
|
|
84
|
+
AND table_name = 'entity_members'
|
|
85
|
+
AND column_name = 'is_active'
|
|
86
|
+
) THEN
|
|
87
|
+
ALTER TABLE ${prefix}entity_members
|
|
88
|
+
ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
|
|
89
|
+
END IF;
|
|
90
|
+
END $$;
|
|
79
91
|
`);
|
|
80
92
|
await client.unsafe(`
|
|
81
93
|
CREATE UNIQUE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_entity_user_idx
|
|
@@ -88,6 +100,10 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
88
100
|
await client.unsafe(`
|
|
89
101
|
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_user_idx
|
|
90
102
|
ON ${prefix}entity_members (user_id)
|
|
103
|
+
`);
|
|
104
|
+
await client.unsafe(`
|
|
105
|
+
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_active_idx
|
|
106
|
+
ON ${prefix}entity_members (is_active)
|
|
91
107
|
`);
|
|
92
108
|
// Create entity_invitations table
|
|
93
109
|
await client.unsafe(`
|
|
@@ -95,9 +111,9 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
95
111
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
96
112
|
entity_id UUID NOT NULL REFERENCES ${prefix}entities(id) ON DELETE CASCADE,
|
|
97
113
|
email VARCHAR(255) NOT NULL,
|
|
98
|
-
role VARCHAR(20) NOT NULL CHECK (role IN ('admin', '
|
|
114
|
+
role VARCHAR(20) NOT NULL CHECK (role IN ('admin', 'member')),
|
|
99
115
|
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'declined', 'expired')),
|
|
100
|
-
invited_by_user_id
|
|
116
|
+
invited_by_user_id VARCHAR(128) NOT NULL,
|
|
101
117
|
token VARCHAR(64) NOT NULL UNIQUE,
|
|
102
118
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
103
119
|
accepted_at TIMESTAMPTZ,
|
|
@@ -156,36 +172,77 @@ async function addEntityIdToProjects(client, prefix, indexPrefix) {
|
|
|
156
172
|
}
|
|
157
173
|
/**
|
|
158
174
|
* Create personal entities for existing users.
|
|
175
|
+
* Uses firebase_uid as the user identifier.
|
|
176
|
+
* Personal entities use role = 'admin' (not 'owner' - owner role is for organizations).
|
|
159
177
|
*/
|
|
160
178
|
async function migrateUsersToPersonalEntities(client, prefix) {
|
|
161
179
|
console.log('Migrating users to personal entities...');
|
|
162
|
-
//
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
SELECT 1 FROM ${prefix}entities e
|
|
170
|
-
WHERE e.owner_user_id = u.id AND e.entity_type = 'personal'
|
|
171
|
-
)
|
|
180
|
+
// Check if user_settings table exists and has firebase_uid column
|
|
181
|
+
const schemaName = prefix.replace('.', '');
|
|
182
|
+
const settingsColumnCheck = await client.unsafe(`
|
|
183
|
+
SELECT column_name FROM information_schema.columns
|
|
184
|
+
WHERE table_schema = '${schemaName}'
|
|
185
|
+
AND table_name = 'user_settings'
|
|
186
|
+
AND column_name IN ('firebase_uid', 'user_id')
|
|
172
187
|
`);
|
|
188
|
+
const settingsHasFirebaseUid = settingsColumnCheck.some((c) => c.column_name === 'firebase_uid');
|
|
189
|
+
const settingsHasUserId = settingsColumnCheck.some((c) => c.column_name === 'user_id');
|
|
190
|
+
const settingsJoinColumn = settingsHasFirebaseUid ? 'firebase_uid' : (settingsHasUserId ? 'user_id' : null);
|
|
191
|
+
// Build query based on whether user_settings exists and which column it has
|
|
192
|
+
let usersQuery;
|
|
193
|
+
if (settingsJoinColumn) {
|
|
194
|
+
usersQuery = `
|
|
195
|
+
SELECT u.firebase_uid, u.email, u.display_name,
|
|
196
|
+
COALESCE(s.organization_path, SUBSTRING(MD5(RANDOM()::TEXT) FROM 1 FOR 8)) as slug_source
|
|
197
|
+
FROM ${prefix}users u
|
|
198
|
+
LEFT JOIN ${prefix}user_settings s ON u.firebase_uid = s.${settingsJoinColumn}
|
|
199
|
+
WHERE u.firebase_uid IS NOT NULL
|
|
200
|
+
AND NOT EXISTS (
|
|
201
|
+
SELECT 1 FROM ${prefix}entity_members em
|
|
202
|
+
INNER JOIN ${prefix}entities e ON em.entity_id = e.id
|
|
203
|
+
WHERE em.user_id = u.firebase_uid
|
|
204
|
+
AND em.role = 'admin'
|
|
205
|
+
AND em.is_active = true
|
|
206
|
+
AND e.entity_type = 'personal'
|
|
207
|
+
)
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// No user_settings table or no matching column - just use users table
|
|
212
|
+
usersQuery = `
|
|
213
|
+
SELECT u.firebase_uid, u.email, u.display_name,
|
|
214
|
+
SUBSTRING(MD5(RANDOM()::TEXT) FROM 1 FOR 8) as slug_source
|
|
215
|
+
FROM ${prefix}users u
|
|
216
|
+
WHERE u.firebase_uid IS NOT NULL
|
|
217
|
+
AND NOT EXISTS (
|
|
218
|
+
SELECT 1 FROM ${prefix}entity_members em
|
|
219
|
+
INNER JOIN ${prefix}entities e ON em.entity_id = e.id
|
|
220
|
+
WHERE em.user_id = u.firebase_uid
|
|
221
|
+
AND em.role = 'admin'
|
|
222
|
+
AND em.is_active = true
|
|
223
|
+
AND e.entity_type = 'personal'
|
|
224
|
+
)
|
|
225
|
+
`;
|
|
226
|
+
}
|
|
227
|
+
// Get users without personal entities (check via entity_members with role = 'admin')
|
|
228
|
+
const usersWithoutEntities = await client.unsafe(usersQuery);
|
|
173
229
|
let migratedCount = 0;
|
|
174
230
|
for (const user of usersWithoutEntities) {
|
|
175
231
|
// Generate a unique slug (8 chars, lowercase alphanumeric)
|
|
176
232
|
const slug = generateSlug(user.slug_source);
|
|
177
233
|
const displayName = user.display_name || user.email?.split('@')[0] || 'Personal';
|
|
234
|
+
const firebaseUid = user.firebase_uid;
|
|
178
235
|
try {
|
|
179
236
|
// Create personal entity
|
|
180
237
|
const [entity] = await client.unsafe(`
|
|
181
|
-
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name
|
|
182
|
-
VALUES ('${slug}', 'personal', '${displayName.replace(/'/g, "''")}'
|
|
238
|
+
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name)
|
|
239
|
+
VALUES ('${slug}', 'personal', '${displayName.replace(/'/g, "''")}')
|
|
183
240
|
RETURNING id
|
|
184
241
|
`);
|
|
185
|
-
// Add user as admin
|
|
242
|
+
// Add user as admin (personal entities use 'admin' role, not 'owner')
|
|
186
243
|
await client.unsafe(`
|
|
187
|
-
INSERT INTO ${prefix}entity_members (entity_id, user_id, role)
|
|
188
|
-
VALUES ('${entity.id}', '${
|
|
244
|
+
INSERT INTO ${prefix}entity_members (entity_id, user_id, role, is_active)
|
|
245
|
+
VALUES ('${entity.id}', '${firebaseUid}', 'admin', true)
|
|
189
246
|
`);
|
|
190
247
|
migratedCount++;
|
|
191
248
|
}
|
|
@@ -194,13 +251,13 @@ async function migrateUsersToPersonalEntities(client, prefix) {
|
|
|
194
251
|
if (error.code === '23505') {
|
|
195
252
|
const newSlug = generateSlug();
|
|
196
253
|
const [entity] = await client.unsafe(`
|
|
197
|
-
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name
|
|
198
|
-
VALUES ('${newSlug}', 'personal', '${displayName.replace(/'/g, "''")}'
|
|
254
|
+
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name)
|
|
255
|
+
VALUES ('${newSlug}', 'personal', '${displayName.replace(/'/g, "''")}')
|
|
199
256
|
RETURNING id
|
|
200
257
|
`);
|
|
201
258
|
await client.unsafe(`
|
|
202
|
-
INSERT INTO ${prefix}entity_members (entity_id, user_id, role)
|
|
203
|
-
VALUES ('${entity.id}', '${
|
|
259
|
+
INSERT INTO ${prefix}entity_members (entity_id, user_id, role, is_active)
|
|
260
|
+
VALUES ('${entity.id}', '${firebaseUid}', 'admin', true)
|
|
204
261
|
`);
|
|
205
262
|
migratedCount++;
|
|
206
263
|
}
|
|
@@ -213,15 +270,19 @@ async function migrateUsersToPersonalEntities(client, prefix) {
|
|
|
213
270
|
}
|
|
214
271
|
/**
|
|
215
272
|
* Populate entity_id for existing projects.
|
|
273
|
+
* Uses entity_members with role = 'admin' to find personal entity membership.
|
|
216
274
|
*/
|
|
217
275
|
async function populateProjectEntityIds(client, prefix) {
|
|
218
276
|
console.log('Populating entity_id for existing projects...');
|
|
219
|
-
// Update projects to use
|
|
277
|
+
// Update projects to use user's personal entity (via entity_members with admin role)
|
|
220
278
|
const result = await client.unsafe(`
|
|
221
279
|
UPDATE ${prefix}projects p
|
|
222
280
|
SET entity_id = e.id
|
|
223
281
|
FROM ${prefix}entities e
|
|
224
|
-
|
|
282
|
+
INNER JOIN ${prefix}entity_members em ON em.entity_id = e.id
|
|
283
|
+
WHERE p.user_id = em.user_id
|
|
284
|
+
AND em.role = 'admin'
|
|
285
|
+
AND em.is_active = true
|
|
225
286
|
AND e.entity_type = 'personal'
|
|
226
287
|
AND p.entity_id IS NULL
|
|
227
288
|
`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"001_add_entities.d.ts","sourceRoot":"","sources":["../../src/migrations/001_add_entities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,MAAM,EAAE,UAAU,CAAC,cAAc,UAAU,CAAC,CAAC,CAAC;IAC9C,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB/E;
|
|
1
|
+
{"version":3,"file":"001_add_entities.d.ts","sourceRoot":"","sources":["../../src/migrations/001_add_entities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,MAAM,EAAE,UAAU,CAAC,cAAc,UAAU,CAAC,CAAC,CAAC;IAC9C,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB/E;AAqUD;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpF"}
|
|
@@ -35,10 +35,11 @@ async function runEntityMigration(config) {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Create the entity tables.
|
|
38
|
+
* Note: Ownership is tracked via entity_members (role = 'owner'), not entities.owner_user_id.
|
|
38
39
|
*/
|
|
39
40
|
async function createEntityTables(client, prefix, indexPrefix) {
|
|
40
41
|
console.log('Creating entity tables...');
|
|
41
|
-
// Create entities table
|
|
42
|
+
// Create entities table (ownership tracked via entity_members)
|
|
42
43
|
await client.unsafe(`
|
|
43
44
|
CREATE TABLE IF NOT EXISTS ${prefix}entities (
|
|
44
45
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
@@ -47,7 +48,6 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
47
48
|
display_name VARCHAR(255) NOT NULL,
|
|
48
49
|
description TEXT,
|
|
49
50
|
avatar_url TEXT,
|
|
50
|
-
owner_user_id UUID NOT NULL,
|
|
51
51
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
52
52
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
53
53
|
)
|
|
@@ -55,27 +55,39 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
55
55
|
await client.unsafe(`
|
|
56
56
|
CREATE UNIQUE INDEX IF NOT EXISTS ${indexPrefix}_entities_slug_idx
|
|
57
57
|
ON ${prefix}entities (entity_slug)
|
|
58
|
-
`);
|
|
59
|
-
await client.unsafe(`
|
|
60
|
-
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entities_owner_idx
|
|
61
|
-
ON ${prefix}entities (owner_user_id)
|
|
62
58
|
`);
|
|
63
59
|
await client.unsafe(`
|
|
64
60
|
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entities_type_idx
|
|
65
61
|
ON ${prefix}entities (entity_type)
|
|
66
62
|
`);
|
|
67
|
-
// Create entity_members table
|
|
63
|
+
// Create entity_members table (tracks all user-entity relationships including ownership)
|
|
68
64
|
await client.unsafe(`
|
|
69
65
|
CREATE TABLE IF NOT EXISTS ${prefix}entity_members (
|
|
70
66
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
71
67
|
entity_id UUID NOT NULL REFERENCES ${prefix}entities(id) ON DELETE CASCADE,
|
|
72
|
-
user_id
|
|
73
|
-
role VARCHAR(20) NOT NULL CHECK (role IN ('
|
|
68
|
+
user_id VARCHAR(128) NOT NULL,
|
|
69
|
+
role VARCHAR(20) NOT NULL CHECK (role IN ('owner', 'admin', 'member')),
|
|
70
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
74
71
|
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
|
75
72
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
76
73
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
77
74
|
UNIQUE(entity_id, user_id)
|
|
78
75
|
)
|
|
76
|
+
`);
|
|
77
|
+
// Add is_active column if it doesn't exist (for upgrading existing tables)
|
|
78
|
+
await client.unsafe(`
|
|
79
|
+
DO $$
|
|
80
|
+
BEGIN
|
|
81
|
+
IF NOT EXISTS (
|
|
82
|
+
SELECT 1 FROM information_schema.columns
|
|
83
|
+
WHERE table_schema = '${prefix.replace('.', '')}'
|
|
84
|
+
AND table_name = 'entity_members'
|
|
85
|
+
AND column_name = 'is_active'
|
|
86
|
+
) THEN
|
|
87
|
+
ALTER TABLE ${prefix}entity_members
|
|
88
|
+
ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
|
|
89
|
+
END IF;
|
|
90
|
+
END $$;
|
|
79
91
|
`);
|
|
80
92
|
await client.unsafe(`
|
|
81
93
|
CREATE UNIQUE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_entity_user_idx
|
|
@@ -88,6 +100,10 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
88
100
|
await client.unsafe(`
|
|
89
101
|
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_user_idx
|
|
90
102
|
ON ${prefix}entity_members (user_id)
|
|
103
|
+
`);
|
|
104
|
+
await client.unsafe(`
|
|
105
|
+
CREATE INDEX IF NOT EXISTS ${indexPrefix}_entity_members_active_idx
|
|
106
|
+
ON ${prefix}entity_members (is_active)
|
|
91
107
|
`);
|
|
92
108
|
// Create entity_invitations table
|
|
93
109
|
await client.unsafe(`
|
|
@@ -95,9 +111,9 @@ async function createEntityTables(client, prefix, indexPrefix) {
|
|
|
95
111
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
96
112
|
entity_id UUID NOT NULL REFERENCES ${prefix}entities(id) ON DELETE CASCADE,
|
|
97
113
|
email VARCHAR(255) NOT NULL,
|
|
98
|
-
role VARCHAR(20) NOT NULL CHECK (role IN ('admin', '
|
|
114
|
+
role VARCHAR(20) NOT NULL CHECK (role IN ('admin', 'member')),
|
|
99
115
|
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'declined', 'expired')),
|
|
100
|
-
invited_by_user_id
|
|
116
|
+
invited_by_user_id VARCHAR(128) NOT NULL,
|
|
101
117
|
token VARCHAR(64) NOT NULL UNIQUE,
|
|
102
118
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
103
119
|
accepted_at TIMESTAMPTZ,
|
|
@@ -156,36 +172,77 @@ async function addEntityIdToProjects(client, prefix, indexPrefix) {
|
|
|
156
172
|
}
|
|
157
173
|
/**
|
|
158
174
|
* Create personal entities for existing users.
|
|
175
|
+
* Uses firebase_uid as the user identifier.
|
|
176
|
+
* Personal entities use role = 'admin' (not 'owner' - owner role is for organizations).
|
|
159
177
|
*/
|
|
160
178
|
async function migrateUsersToPersonalEntities(client, prefix) {
|
|
161
179
|
console.log('Migrating users to personal entities...');
|
|
162
|
-
//
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
SELECT 1 FROM ${prefix}entities e
|
|
170
|
-
WHERE e.owner_user_id = u.id AND e.entity_type = 'personal'
|
|
171
|
-
)
|
|
180
|
+
// Check if user_settings table exists and has firebase_uid column
|
|
181
|
+
const schemaName = prefix.replace('.', '');
|
|
182
|
+
const settingsColumnCheck = await client.unsafe(`
|
|
183
|
+
SELECT column_name FROM information_schema.columns
|
|
184
|
+
WHERE table_schema = '${schemaName}'
|
|
185
|
+
AND table_name = 'user_settings'
|
|
186
|
+
AND column_name IN ('firebase_uid', 'user_id')
|
|
172
187
|
`);
|
|
188
|
+
const settingsHasFirebaseUid = settingsColumnCheck.some((c) => c.column_name === 'firebase_uid');
|
|
189
|
+
const settingsHasUserId = settingsColumnCheck.some((c) => c.column_name === 'user_id');
|
|
190
|
+
const settingsJoinColumn = settingsHasFirebaseUid ? 'firebase_uid' : (settingsHasUserId ? 'user_id' : null);
|
|
191
|
+
// Build query based on whether user_settings exists and which column it has
|
|
192
|
+
let usersQuery;
|
|
193
|
+
if (settingsJoinColumn) {
|
|
194
|
+
usersQuery = `
|
|
195
|
+
SELECT u.firebase_uid, u.email, u.display_name,
|
|
196
|
+
COALESCE(s.organization_path, SUBSTRING(MD5(RANDOM()::TEXT) FROM 1 FOR 8)) as slug_source
|
|
197
|
+
FROM ${prefix}users u
|
|
198
|
+
LEFT JOIN ${prefix}user_settings s ON u.firebase_uid = s.${settingsJoinColumn}
|
|
199
|
+
WHERE u.firebase_uid IS NOT NULL
|
|
200
|
+
AND NOT EXISTS (
|
|
201
|
+
SELECT 1 FROM ${prefix}entity_members em
|
|
202
|
+
INNER JOIN ${prefix}entities e ON em.entity_id = e.id
|
|
203
|
+
WHERE em.user_id = u.firebase_uid
|
|
204
|
+
AND em.role = 'admin'
|
|
205
|
+
AND em.is_active = true
|
|
206
|
+
AND e.entity_type = 'personal'
|
|
207
|
+
)
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// No user_settings table or no matching column - just use users table
|
|
212
|
+
usersQuery = `
|
|
213
|
+
SELECT u.firebase_uid, u.email, u.display_name,
|
|
214
|
+
SUBSTRING(MD5(RANDOM()::TEXT) FROM 1 FOR 8) as slug_source
|
|
215
|
+
FROM ${prefix}users u
|
|
216
|
+
WHERE u.firebase_uid IS NOT NULL
|
|
217
|
+
AND NOT EXISTS (
|
|
218
|
+
SELECT 1 FROM ${prefix}entity_members em
|
|
219
|
+
INNER JOIN ${prefix}entities e ON em.entity_id = e.id
|
|
220
|
+
WHERE em.user_id = u.firebase_uid
|
|
221
|
+
AND em.role = 'admin'
|
|
222
|
+
AND em.is_active = true
|
|
223
|
+
AND e.entity_type = 'personal'
|
|
224
|
+
)
|
|
225
|
+
`;
|
|
226
|
+
}
|
|
227
|
+
// Get users without personal entities (check via entity_members with role = 'admin')
|
|
228
|
+
const usersWithoutEntities = await client.unsafe(usersQuery);
|
|
173
229
|
let migratedCount = 0;
|
|
174
230
|
for (const user of usersWithoutEntities) {
|
|
175
231
|
// Generate a unique slug (8 chars, lowercase alphanumeric)
|
|
176
232
|
const slug = generateSlug(user.slug_source);
|
|
177
233
|
const displayName = user.display_name || user.email?.split('@')[0] || 'Personal';
|
|
234
|
+
const firebaseUid = user.firebase_uid;
|
|
178
235
|
try {
|
|
179
236
|
// Create personal entity
|
|
180
237
|
const [entity] = await client.unsafe(`
|
|
181
|
-
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name
|
|
182
|
-
VALUES ('${slug}', 'personal', '${displayName.replace(/'/g, "''")}'
|
|
238
|
+
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name)
|
|
239
|
+
VALUES ('${slug}', 'personal', '${displayName.replace(/'/g, "''")}')
|
|
183
240
|
RETURNING id
|
|
184
241
|
`);
|
|
185
|
-
// Add user as admin
|
|
242
|
+
// Add user as admin (personal entities use 'admin' role, not 'owner')
|
|
186
243
|
await client.unsafe(`
|
|
187
|
-
INSERT INTO ${prefix}entity_members (entity_id, user_id, role)
|
|
188
|
-
VALUES ('${entity.id}', '${
|
|
244
|
+
INSERT INTO ${prefix}entity_members (entity_id, user_id, role, is_active)
|
|
245
|
+
VALUES ('${entity.id}', '${firebaseUid}', 'admin', true)
|
|
189
246
|
`);
|
|
190
247
|
migratedCount++;
|
|
191
248
|
}
|
|
@@ -194,13 +251,13 @@ async function migrateUsersToPersonalEntities(client, prefix) {
|
|
|
194
251
|
if (error.code === '23505') {
|
|
195
252
|
const newSlug = generateSlug();
|
|
196
253
|
const [entity] = await client.unsafe(`
|
|
197
|
-
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name
|
|
198
|
-
VALUES ('${newSlug}', 'personal', '${displayName.replace(/'/g, "''")}'
|
|
254
|
+
INSERT INTO ${prefix}entities (entity_slug, entity_type, display_name)
|
|
255
|
+
VALUES ('${newSlug}', 'personal', '${displayName.replace(/'/g, "''")}')
|
|
199
256
|
RETURNING id
|
|
200
257
|
`);
|
|
201
258
|
await client.unsafe(`
|
|
202
|
-
INSERT INTO ${prefix}entity_members (entity_id, user_id, role)
|
|
203
|
-
VALUES ('${entity.id}', '${
|
|
259
|
+
INSERT INTO ${prefix}entity_members (entity_id, user_id, role, is_active)
|
|
260
|
+
VALUES ('${entity.id}', '${firebaseUid}', 'admin', true)
|
|
204
261
|
`);
|
|
205
262
|
migratedCount++;
|
|
206
263
|
}
|
|
@@ -213,15 +270,19 @@ async function migrateUsersToPersonalEntities(client, prefix) {
|
|
|
213
270
|
}
|
|
214
271
|
/**
|
|
215
272
|
* Populate entity_id for existing projects.
|
|
273
|
+
* Uses entity_members with role = 'admin' to find personal entity membership.
|
|
216
274
|
*/
|
|
217
275
|
async function populateProjectEntityIds(client, prefix) {
|
|
218
276
|
console.log('Populating entity_id for existing projects...');
|
|
219
|
-
// Update projects to use
|
|
277
|
+
// Update projects to use user's personal entity (via entity_members with admin role)
|
|
220
278
|
const result = await client.unsafe(`
|
|
221
279
|
UPDATE ${prefix}projects p
|
|
222
280
|
SET entity_id = e.id
|
|
223
281
|
FROM ${prefix}entities e
|
|
224
|
-
|
|
282
|
+
INNER JOIN ${prefix}entity_members em ON em.entity_id = e.id
|
|
283
|
+
WHERE p.user_id = em.user_id
|
|
284
|
+
AND em.role = 'admin'
|
|
285
|
+
AND em.is_active = true
|
|
225
286
|
AND e.entity_type = 'personal'
|
|
226
287
|
AND p.entity_id IS NULL
|
|
227
288
|
`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"001_add_entities.js","sourceRoot":"","sources":["../../src/migrations/001_add_entities.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAiBH,gDAuBC;
|
|
1
|
+
{"version":3,"file":"001_add_entities.js","sourceRoot":"","sources":["../../src/migrations/001_add_entities.ts"],"names":[],"mappings":"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"}
|