@wirechunk/cli 0.0.1-rc.2 → 0.0.1

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/build/main.js CHANGED
@@ -3892,7 +3892,7 @@ function customAlphabet(alphabet2, size = 21) {
3892
3892
  return customRandom(alphabet2, size, random);
3893
3893
  }
3894
3894
  const alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
3895
- customAlphabet(alphabet, 22);
3895
+ const cleanSmallId = customAlphabet(alphabet, 22);
3896
3896
  const tinyAlphabet = "23456789abcdefghijkmnopqrstuvwxyz";
3897
3897
  const startWithLowercaseLetterPattern = /^[a-z]/;
3898
3898
  const startsWithLowercaseLetter = (s) => startWithLowercaseLetterPattern.test(s);
@@ -57347,9 +57347,6 @@ const detailedUniqueIntegrityConstraintViolationError = (error2) => {
57347
57347
  return message;
57348
57348
  };
57349
57349
  const isDuplicateDatabaseError = (error2) => !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === "42P04";
57350
- const insertOrgResult = z.object({
57351
- id: z.string()
57352
- });
57353
57350
  const insertUserResult = z.object({
57354
57351
  id: z.string()
57355
57352
  });
@@ -57396,14 +57393,14 @@ const createUser = async (opts, env2) => {
57396
57393
  throw new Error("Either --org-id or --platform-id must be specified");
57397
57394
  }
57398
57395
  platformId = await db2.maybeOneFirst(
57399
- distExports$1.sql.type(findOrgResult)`select "platformId" from "Organizations" where "id" = ${orgId}`
57396
+ distExports$1.sql.type(findOrgResult)`select "platformId" from "Orgs" where "id" = ${orgId}`
57400
57397
  );
57401
57398
  if (!platformId) {
57402
57399
  throw new Error(`No org found with ID ${orgId}`);
57403
57400
  }
57404
57401
  } else if (orgId) {
57405
57402
  const orgPlatformId = await db2.maybeOneFirst(
57406
- distExports$1.sql.type(findOrgResult)`select "platformId" from "Organizations" where "id" = ${orgId}`
57403
+ distExports$1.sql.type(findOrgResult)`select "platformId" from "Orgs" where "id" = ${orgId}`
57407
57404
  );
57408
57405
  if (!orgPlatformId) {
57409
57406
  throw new Error(`No org found with ID ${orgId}`);
@@ -57424,10 +57421,11 @@ const createUser = async (opts, env2) => {
57424
57421
  console.log(`Found platform ${platform.name} (ID ${platform.id})`);
57425
57422
  }
57426
57423
  if (!orgId) {
57427
- orgId = await db2.oneFirst(
57424
+ orgId = cleanSmallId();
57425
+ await db2.maybeOne(
57428
57426
  distExports$1.sql.type(
57429
- insertOrgResult
57430
- )`insert into "Organizations" ("platformId") values (${platform.id}) returning "id"`
57427
+ voidSelectSchema
57428
+ )`insert into "Orgs" ("id", "platformId") values (${orgId}, ${platform.id})`
57431
57429
  );
57432
57430
  if (opts.verbose) {
57433
57431
  console.log(`Created org ID ${orgId}`);
@@ -57437,8 +57435,15 @@ const createUser = async (opts, env2) => {
57437
57435
  const user2 = await db2.one(
57438
57436
  distExports$1.sql.type(
57439
57437
  insertUserResult
57440
- )`insert into "Users" ("platformId", "email", "emailVerified", "password", "passwordStatus", "orgId", "orgPrimary", "role", "status", "firstName", "lastName") values (${platformId}, ${email}, ${opts.emailVerified}, ${password}, 'Ok', ${orgId}, ${orgPrimary}, ${role}, ${status}, ${firstName}, ${lastName}) returning "id"`
57438
+ )`insert into "Users" ("platformId", "email", "emailVerified", "password", "passwordStatus", "orgId", "role", "status", "firstName", "lastName") values (${platformId}, ${email}, ${opts.emailVerified}, ${password}, 'Ok', ${orgId}, ${role}, ${status}, ${firstName}, ${lastName}) returning "id"`
57441
57439
  );
57440
+ if (orgPrimary) {
57441
+ await db2.maybeOne(
57442
+ distExports$1.sql.type(
57443
+ voidSelectSchema
57444
+ )`update "Orgs" set "primaryUserId" = ${user2.id} where "id" = ${orgId}`
57445
+ );
57446
+ }
57442
57447
  return user2;
57443
57448
  });
57444
57449
  console.log(`Created user (ID ${user.id})`);
@@ -57451,13 +57456,107 @@ const createUser = async (opts, env2) => {
57451
57456
  process.exit(1);
57452
57457
  }
57453
57458
  };
57454
- const findUserSchema = z.object({
57459
+ const Permission = {
57460
+ /** Create (i.e., add) extensions. */
57461
+ CreateExtension: "CreateExtension",
57462
+ /** Create sites. */
57463
+ CreateSite: "CreateSite",
57464
+ /** Create page and form templates. */
57465
+ CreateTemplate: "CreateTemplate",
57466
+ /** Create a user in any org. */
57467
+ CreateUser: "CreateUser",
57468
+ /** Edit or manage everything else not covered by other permissions. */
57469
+ Edit: "Edit",
57470
+ /** Edit, including creating and deleting, any component. */
57471
+ EditComponent: "EditComponent",
57472
+ /** Edit, including creating and deleting, any course. */
57473
+ EditCourse: "EditCourse",
57474
+ /** Edit, including creating and deleting, any custom component. */
57475
+ EditCustomComponent: "EditCustomComponent",
57476
+ /** Edit, including creating and deleting, any custom field. */
57477
+ EditCustomField: "EditCustomField",
57478
+ /** Edit any customer site, including its pages and forms, but not necessarily domain. */
57479
+ EditCustomerSite: "EditCustomerSite",
57480
+ /** Edit any extension. */
57481
+ EditExtension: "EditExtension",
57482
+ /** Edit any help ticket's status. */
57483
+ EditHelpTicketStatus: "EditHelpTicketStatus",
57484
+ /** Edit any platform site, including its pages and forms, but not necessarily domain. */
57485
+ EditPlatformSite: "EditPlatformSite",
57486
+ /** Edit, including creating and deleting, any sequence. */
57487
+ EditSequence: "EditSequence",
57488
+ /** Edit any user's position in a sequence. */
57489
+ EditSequenceUser: "EditSequenceUser",
57490
+ /** Edit any site's settings, pages, forms, and layouts. */
57491
+ EditSite: "EditSite",
57492
+ /** Edit any site's domain. */
57493
+ EditSiteDomain: "EditSiteDomain",
57494
+ /** Edit any site's TLS certificate, including creating and deleting certificates. Does not including editing TLS certificates. */
57495
+ EditSiteTlsCertificate: "EditSiteTlsCertificate",
57496
+ /** Edit any subscription. */
57497
+ EditSubscription: "EditSubscription",
57498
+ /** Edit any page and form template. */
57499
+ EditTemplate: "EditTemplate",
57500
+ /** Edit any user's email address. */
57501
+ EditUserEmail: "EditUserEmail",
57502
+ /** Edit which org any user is in and whether a user is an org owner. */
57503
+ EditUserOrg: "EditUserOrg",
57504
+ /** Edit any user's first and last name. */
57505
+ EditUserProfile: "EditUserProfile",
57506
+ /** Edit any user's role. */
57507
+ EditUserRole: "EditUserRole",
57508
+ /** Edit any user's status. */
57509
+ EditUserStatus: "EditUserStatus",
57510
+ /** Sync any form template to forms. */
57511
+ SyncFormTemplateToForms: "SyncFormTemplateToForms",
57512
+ /** Sync any page template to pages. */
57513
+ SyncPageTemplateToPages: "SyncPageTemplateToPages",
57514
+ /** View anything except for sites. */
57515
+ View: "View",
57516
+ /** View any course. */
57517
+ ViewCourse: "ViewCourse",
57518
+ /** View any extension. */
57519
+ ViewExtension: "ViewExtension",
57520
+ /** View any site, including pages, forms, and layouts, and components. */
57521
+ ViewSite: "ViewSite",
57522
+ /** View any page or form template. */
57523
+ ViewTemplate: "ViewTemplate"
57524
+ };
57525
+ const allPermissions = Object.values(Permission);
57526
+ const revokeAllUserPlatformPermissions = async ({
57527
+ platformAdminId
57528
+ }, db) => {
57529
+ await db.query(
57530
+ distExports$1.sql.type(
57531
+ voidSelectSchema
57532
+ )`delete from "PlatformAdminPermissions" where "id" = ${platformAdminId}`
57533
+ );
57534
+ };
57535
+ const grantAllUserPlatformPermissions = async ({
57536
+ platformAdminId
57537
+ }, db) => {
57538
+ await db.query(
57539
+ distExports$1.sql.type(
57540
+ voidSelectSchema
57541
+ )`insert into "PlatformAdminPermissions" ("id", "platformAdminId", "permission") values ${distExports$1.sql.join(
57542
+ allPermissions.map(
57543
+ (permission) => distExports$1.sql.fragment`(${cleanSmallId()}, ${platformAdminId}, ${permission})`
57544
+ ),
57545
+ distExports$1.sql.fragment`,`
57546
+ )} on conflict ("platformAdminId", "permission") do nothing`
57547
+ );
57548
+ };
57549
+ const findPlatformAdminSchema = z.object({
57455
57550
  id: z.string(),
57456
- platformId: z.string()
57551
+ platformId: z.string(),
57552
+ active: z.boolean()
57553
+ });
57554
+ const findUserSchema = z.object({
57555
+ id: z.string()
57457
57556
  });
57458
57557
  const editAdmin = async (opts, env2) => {
57459
57558
  const db = await distExports$1.createPool(requireCoreDbUrl(env2));
57460
- const { platformId, userId, owner, revokeAllPermissions } = opts;
57559
+ const { platformId, userId, owner, active, revokeAllPermissions } = opts;
57461
57560
  if (owner && revokeAllPermissions) {
57462
57561
  console.error(
57463
57562
  "Cannot set a user as a platform owner and revoke all permissions at the same time"
@@ -57466,9 +57565,9 @@ const editAdmin = async (opts, env2) => {
57466
57565
  }
57467
57566
  try {
57468
57567
  await db.transaction(async (db2) => {
57469
- const platformAdmin = await db2.maybeOne(
57568
+ let platformAdmin = await db2.maybeOne(
57470
57569
  distExports$1.sql.type(
57471
- findUserSchema
57570
+ findPlatformAdminSchema
57472
57571
  )`select "id" from "PlatformAdmins" where "platformId" = ${platformId} and "userId" = ${userId}`
57473
57572
  );
57474
57573
  if (!platformAdmin) {
@@ -57479,6 +57578,66 @@ const editAdmin = async (opts, env2) => {
57479
57578
  throw new Error(`User with ID ${userId} not found`);
57480
57579
  }
57481
57580
  }
57581
+ if (owner) {
57582
+ if (!platformAdmin) {
57583
+ platformAdmin = await db2.one(
57584
+ distExports$1.sql.type(findPlatformAdminSchema)`
57585
+ insert into "PlatformAdmins" ("id", "platformId", "userId", "owner", "active")
57586
+ values (${cleanSmallId()}, ${platformId}, ${userId}, ${active ?? true}, true)
57587
+ returning "id", "platformId", "active"
57588
+ `
57589
+ );
57590
+ }
57591
+ await grantAllUserPlatformPermissions({ platformAdminId: platformAdmin.id }, db2);
57592
+ if (opts.verbose) {
57593
+ console.log("Set the user as an owner on the platform");
57594
+ }
57595
+ } else if (owner === false) {
57596
+ if (platformAdmin) {
57597
+ await db2.query(
57598
+ distExports$1.sql.type(voidSelectSchema)`
57599
+ update "PlatformAdmins"
57600
+ set "owner" = false
57601
+ where "id" = ${platformAdmin.id}
57602
+ `
57603
+ );
57604
+ if (opts.verbose) {
57605
+ console.log("Removed the user’s owner privileges on the platform");
57606
+ }
57607
+ } else {
57608
+ console.log("This user is not an admin on this platform");
57609
+ }
57610
+ }
57611
+ if (typeof active === "boolean") {
57612
+ if (platformAdmin) {
57613
+ await db2.query(
57614
+ distExports$1.sql.type(voidSelectSchema)`
57615
+ update "PlatformAdmins"
57616
+ set "active" = ${active}
57617
+ where "id" = ${platformAdmin.id}
57618
+ `
57619
+ );
57620
+ } else {
57621
+ if (active) {
57622
+ await db2.one(
57623
+ distExports$1.sql.type(voidSelectSchema)`
57624
+ insert into "PlatformAdmins" ("id", "platformId", "userId", "owner", "active")
57625
+ values (${cleanSmallId()}, ${platformId}, ${userId}, false, ${active})
57626
+ `
57627
+ );
57628
+ } else {
57629
+ console.log("This user is not an admin on this platform");
57630
+ }
57631
+ }
57632
+ }
57633
+ if (revokeAllPermissions) {
57634
+ if (platformAdmin) {
57635
+ await revokeAllUserPlatformPermissions({ platformAdminId: platformAdmin.id }, db2);
57636
+ console.log("Revoked all platform permissions of user");
57637
+ } else {
57638
+ console.log("This user is not an admin on this platform");
57639
+ }
57640
+ }
57482
57641
  });
57483
57642
  } catch (e) {
57484
57643
  if (e instanceof distExports$1.UniqueIntegrityConstraintViolationError) {
@@ -57654,6 +57813,9 @@ const initDb = async (opts, env2) => {
57654
57813
  end if;
57655
57814
  end; $$
57656
57815
  `);
57816
+ await db.query(distExports$1.sql.unsafe`
57817
+ grant ${extRoleIdent} to ${distExports$1.sql.identifier([coreDbUrlObject.username])}
57818
+ `);
57657
57819
  await db.query(distExports$1.sql.unsafe`
57658
57820
  grant connect, create, temporary on database ${distExports$1.sql.identifier([extDb.dbName])} to ${extRoleIdent}
57659
57821
  `);
@@ -57730,9 +57892,11 @@ extDev.command("db-connect-info").description(
57730
57892
  "--extension-id <string>",
57731
57893
  "the ID of the extension, can be set with an EXTENSION_ID environment variable instead"
57732
57894
  ).action(withOptionsAndEnv(dbConnectInfo));
57733
- extDev.command("init-db").description("initialize a development database for an extension, useful for testing").option(
57895
+ extDev.command("init-db").description(
57896
+ "initialize a development database for an extension, useful for testing, assumes the extension role exists"
57897
+ ).option(
57734
57898
  "--extension-id <string>",
57735
57899
  "the ID of the extension, can be set with an EXTENSION_ID environment variable instead"
57736
57900
  ).option("--db-name <string>", "a custom name for the database, applicable only for testing").action(withOptionsAndEnv(initDb));
57737
- program.command("edit-admin").description("edit a platform admin user").requiredOption("--platform-id <string>", "the ID of the platform to edit").requiredOption("--user-id <string>", "the ID of the admin user to edit").option("--owner", "grants the user full permission to manage everything on the platform").option("--revoke-all-permissions", "revokes all permission of the user on their platform").action(withOptionsAndEnv(editAdmin));
57901
+ program.command("edit-admin").description("edit a platform admin user or make a user a platform admin").requiredOption("--platform-id <string>", "the ID of the platform to edit").requiredOption("--user-id <string>", "the ID of the admin user to edit").option("--owner", "grants the user full permission to manage everything on the platform").option("--no-owner", "removes owner privileges on the platform").option("--active", "activates or deactivates the user’s admin access on the platform").option("--no-active", "deactivates the user’s admin access on the platform").option("--revoke-all-permissions", "revokes all permission of the user on their platform").action(withOptionsAndEnv(editAdmin));
57738
57902
  await program.parseAsync();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirechunk/cli",
3
- "version": "0.0.1-rc.2",
3
+ "version": "0.0.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,4 +1,5 @@
1
1
  import { hashPassword, validatePasswordComplexity } from '@wirechunk/backend-lib/passwords.ts';
2
+ import { cleanSmallId } from '@wirechunk/lib/clean-small-id.ts';
2
3
  import { normalizeEmailAddress } from '@wirechunk/lib/emails.ts';
3
4
  import { createPool, sql, UniqueIntegrityConstraintViolationError } from 'slonik';
4
5
  import { z } from 'zod';
@@ -6,10 +7,7 @@ import type { Env } from '../env.ts';
6
7
  import { requireCoreDbUrl } from '../env.ts';
7
8
  import { detailedUniqueIntegrityConstraintViolationError } from '../errors.ts';
8
9
  import type { WithGlobalOptions } from '../global-options.ts';
9
-
10
- const insertOrgResult = z.object({
11
- id: z.string(),
12
- });
10
+ import { voidSelectSchema } from '../util.ts';
13
11
 
14
12
  const insertUserResult = z.object({
15
13
  id: z.string(),
@@ -78,7 +76,7 @@ export const createUser = async (
78
76
  throw new Error('Either --org-id or --platform-id must be specified');
79
77
  }
80
78
  platformId = await db.maybeOneFirst(
81
- sql.type(findOrgResult)`select "platformId" from "Organizations" where "id" = ${orgId}`,
79
+ sql.type(findOrgResult)`select "platformId" from "Orgs" where "id" = ${orgId}`,
82
80
  );
83
81
  if (!platformId) {
84
82
  throw new Error(`No org found with ID ${orgId}`);
@@ -86,7 +84,7 @@ export const createUser = async (
86
84
  } else if (orgId) {
87
85
  // Verify that the specified org belongs to the specified platform.
88
86
  const orgPlatformId = await db.maybeOneFirst(
89
- sql.type(findOrgResult)`select "platformId" from "Organizations" where "id" = ${orgId}`,
87
+ sql.type(findOrgResult)`select "platformId" from "Orgs" where "id" = ${orgId}`,
90
88
  );
91
89
  if (!orgPlatformId) {
92
90
  throw new Error(`No org found with ID ${orgId}`);
@@ -107,10 +105,11 @@ export const createUser = async (
107
105
  console.log(`Found platform ${platform.name} (ID ${platform.id})`);
108
106
  }
109
107
  if (!orgId) {
110
- orgId = await db.oneFirst(
108
+ orgId = cleanSmallId();
109
+ await db.maybeOne(
111
110
  sql.type(
112
- insertOrgResult,
113
- )`insert into "Organizations" ("platformId") values (${platform.id}) returning "id"`,
111
+ voidSelectSchema,
112
+ )`insert into "Orgs" ("id", "platformId") values (${orgId}, ${platform.id})`,
114
113
  );
115
114
  if (opts.verbose) {
116
115
  console.log(`Created org ID ${orgId}`);
@@ -121,12 +120,16 @@ export const createUser = async (
121
120
  const user = await db.one(
122
121
  sql.type(
123
122
  insertUserResult,
124
- )`insert into "Users" ("platformId", "email", "emailVerified", "password", "passwordStatus", "orgId", "orgPrimary", "role", "status", "firstName", "lastName") values (${platformId}, ${email}, ${opts.emailVerified}, ${password}, 'Ok', ${orgId}, ${orgPrimary}, ${role}, ${status}, ${firstName}, ${lastName}) returning "id"`,
123
+ )`insert into "Users" ("platformId", "email", "emailVerified", "password", "passwordStatus", "orgId", "role", "status", "firstName", "lastName") values (${platformId}, ${email}, ${opts.emailVerified}, ${password}, 'Ok', ${orgId}, ${role}, ${status}, ${firstName}, ${lastName}) returning "id"`,
125
124
  );
126
125
 
127
- // if (opts.admin) {
128
- // await grantAllUserPlatformPermissions({ userId: user.id, platformId }, db);
129
- // }
126
+ if (orgPrimary) {
127
+ await db.maybeOne(
128
+ sql.type(
129
+ voidSelectSchema,
130
+ )`update "Orgs" set "primaryUserId" = ${user.id} where "id" = ${orgId}`,
131
+ );
132
+ }
130
133
 
131
134
  return user;
132
135
  });
@@ -1,19 +1,31 @@
1
+ import { cleanSmallId } from '@wirechunk/lib/clean-small-id.ts';
1
2
  import { createPool, sql, UniqueIntegrityConstraintViolationError } from 'slonik';
2
3
  import { z } from 'zod';
3
4
  import type { Env } from '../env.ts';
4
5
  import { requireCoreDbUrl } from '../env.ts';
5
6
  import { detailedUniqueIntegrityConstraintViolationError } from '../errors.ts';
6
7
  import type { WithGlobalOptions } from '../global-options.ts';
8
+ import {
9
+ grantAllUserPlatformPermissions,
10
+ revokeAllUserPlatformPermissions,
11
+ } from '../users/permissions.ts';
12
+ import { voidSelectSchema } from '../util.ts';
7
13
 
8
- const findUserSchema = z.object({
14
+ const findPlatformAdminSchema = z.object({
9
15
  id: z.string(),
10
16
  platformId: z.string(),
17
+ active: z.boolean(),
18
+ });
19
+
20
+ const findUserSchema = z.object({
21
+ id: z.string(),
11
22
  });
12
23
 
13
24
  type EditAdminOptions = {
14
25
  platformId: string;
15
26
  userId: string;
16
27
  owner?: boolean;
28
+ active?: boolean;
17
29
  revokeAllPermissions?: boolean;
18
30
  };
19
31
 
@@ -22,7 +34,7 @@ export const editAdmin = async (
22
34
  env: Env,
23
35
  ): Promise<void> => {
24
36
  const db = await createPool(requireCoreDbUrl(env));
25
- const { platformId, userId, owner, revokeAllPermissions } = opts;
37
+ const { platformId, userId, owner, active, revokeAllPermissions } = opts;
26
38
 
27
39
  if (owner && revokeAllPermissions) {
28
40
  console.error(
@@ -33,9 +45,9 @@ export const editAdmin = async (
33
45
 
34
46
  try {
35
47
  await db.transaction(async (db) => {
36
- const platformAdmin = await db.maybeOne(
48
+ let platformAdmin = await db.maybeOne(
37
49
  sql.type(
38
- findUserSchema,
50
+ findPlatformAdminSchema,
39
51
  )`select "id" from "PlatformAdmins" where "platformId" = ${platformId} and "userId" = ${userId}`,
40
52
  );
41
53
  if (!platformAdmin) {
@@ -46,17 +58,67 @@ export const editAdmin = async (
46
58
  throw new Error(`User with ID ${userId} not found`);
47
59
  }
48
60
  }
49
-
50
- // TODO
51
-
52
- // if (owner) {
53
- // await grantAllUserPlatformPermissions({ userId: id, platformId: user.platformId }, db);
54
- // console.log('Set user as a platform admin');
55
- // }
56
- // if (revokeAllPermissions) {
57
- // await revokeAllUserPlatformPermissions({ userId: id }, db);
58
- // console.log('Revoked all platform permissions of user');
59
- // }
61
+ if (owner) {
62
+ if (!platformAdmin) {
63
+ platformAdmin = await db.one(
64
+ sql.type(findPlatformAdminSchema)`
65
+ insert into "PlatformAdmins" ("id", "platformId", "userId", "owner", "active")
66
+ values (${cleanSmallId()}, ${platformId}, ${userId}, ${active ?? true}, true)
67
+ returning "id", "platformId", "active"
68
+ `,
69
+ );
70
+ }
71
+ await grantAllUserPlatformPermissions({ platformAdminId: platformAdmin.id }, db);
72
+ if (opts.verbose) {
73
+ console.log('Set the user as an owner on the platform');
74
+ }
75
+ } else if (owner === false) {
76
+ if (platformAdmin) {
77
+ await db.query(
78
+ sql.type(voidSelectSchema)`
79
+ update "PlatformAdmins"
80
+ set "owner" = false
81
+ where "id" = ${platformAdmin.id}
82
+ `,
83
+ );
84
+ if (opts.verbose) {
85
+ console.log('Removed the user’s owner privileges on the platform');
86
+ }
87
+ } else {
88
+ console.log('This user is not an admin on this platform');
89
+ }
90
+ }
91
+ if (typeof active === 'boolean') {
92
+ if (platformAdmin) {
93
+ await db.query(
94
+ sql.type(voidSelectSchema)`
95
+ update "PlatformAdmins"
96
+ set "active" = ${active}
97
+ where "id" = ${platformAdmin.id}
98
+ `,
99
+ );
100
+ } else {
101
+ if (active) {
102
+ // Automatically create a platform admin.
103
+ await db.one(
104
+ sql.type(voidSelectSchema)`
105
+ insert into "PlatformAdmins" ("id", "platformId", "userId", "owner", "active")
106
+ values (${cleanSmallId()}, ${platformId}, ${userId}, false, ${active})
107
+ `,
108
+ );
109
+ } else {
110
+ console.log('This user is not an admin on this platform');
111
+ }
112
+ }
113
+ }
114
+ if (revokeAllPermissions) {
115
+ if (platformAdmin) {
116
+ await revokeAllUserPlatformPermissions({ platformAdminId: platformAdmin.id }, db);
117
+ console.log('Revoked all platform permissions of user');
118
+ } else {
119
+ console.log('This user is not an admin on this platform');
120
+ }
121
+ }
60
122
  });
61
123
  } catch (e) {
62
124
  if (e instanceof UniqueIntegrityConstraintViolationError) {
@@ -190,6 +190,9 @@ export const initDb = async (
190
190
  end if;
191
191
  end; $$
192
192
  `);
193
+ await db.query(sql.unsafe`
194
+ grant ${extRoleIdent} to ${sql.identifier([coreDbUrlObject.username])}
195
+ `);
193
196
 
194
197
  await db.query(sql.unsafe`
195
198
  grant connect, create, temporary on database ${sql.identifier([extDb.dbName])} to ${extRoleIdent}
package/src/main.ts CHANGED
@@ -106,7 +106,9 @@ extDev
106
106
 
107
107
  extDev
108
108
  .command('init-db')
109
- .description('initialize a development database for an extension, useful for testing')
109
+ .description(
110
+ 'initialize a development database for an extension, useful for testing, assumes the extension role exists',
111
+ )
110
112
  .option(
111
113
  '--extension-id <string>',
112
114
  'the ID of the extension, can be set with an EXTENSION_ID environment variable instead',
@@ -116,10 +118,13 @@ extDev
116
118
 
117
119
  program
118
120
  .command('edit-admin')
119
- .description('edit a platform admin user')
121
+ .description('edit a platform admin user or make a user a platform admin')
120
122
  .requiredOption('--platform-id <string>', 'the ID of the platform to edit')
121
123
  .requiredOption('--user-id <string>', 'the ID of the admin user to edit')
122
124
  .option('--owner', 'grants the user full permission to manage everything on the platform')
125
+ .option('--no-owner', 'removes owner privileges on the platform')
126
+ .option('--active', 'activates or deactivates the user’s admin access on the platform')
127
+ .option('--no-active', 'deactivates the user’s admin access on the platform')
123
128
  .option('--revoke-all-permissions', 'revokes all permission of the user on their platform')
124
129
  .action(withOptionsAndEnv(editAdmin));
125
130
 
@@ -1,3 +1,4 @@
1
+ import { cleanSmallId } from '@wirechunk/lib/clean-small-id.ts';
1
2
  import { Permission } from '@wirechunk/lib/graphql-api-enums.ts';
2
3
  import type { CommonQueryMethods } from 'slonik';
3
4
  import { sql } from 'slonik';
@@ -7,33 +8,35 @@ export const allPermissions = Object.values(Permission);
7
8
 
8
9
  export const revokeAllUserPlatformPermissions = async (
9
10
  {
10
- userId,
11
+ platformAdminId,
11
12
  }: {
12
- userId: string;
13
+ platformAdminId: string;
13
14
  },
14
15
  db: CommonQueryMethods,
15
16
  ): Promise<void> => {
16
17
  await db.query(
17
- sql.type(voidSelectSchema)`delete from "UserPlatformPermissions" where "userId" = ${userId}`,
18
+ sql.type(
19
+ voidSelectSchema,
20
+ )`delete from "PlatformAdminPermissions" where "id" = ${platformAdminId}`,
18
21
  );
19
22
  };
20
23
 
21
24
  export const grantAllUserPlatformPermissions = async (
22
25
  {
23
- userId,
24
- platformId,
26
+ platformAdminId,
25
27
  }: {
26
- userId: string;
27
- platformId: string;
28
+ platformAdminId: string;
28
29
  },
29
30
  db: CommonQueryMethods,
30
31
  ): Promise<void> => {
31
32
  await db.query(
32
33
  sql.type(
33
34
  voidSelectSchema,
34
- )`insert into "UserPlatformPermissions" ("userId", "platformId", "permission") values ${sql.join(
35
- allPermissions.map((permission) => sql.fragment`(${userId}, ${platformId}, ${permission})`),
35
+ )`insert into "PlatformAdminPermissions" ("id", "platformAdminId", "permission") values ${sql.join(
36
+ allPermissions.map(
37
+ (permission) => sql.fragment`(${cleanSmallId()}, ${platformAdminId}, ${permission})`,
38
+ ),
36
39
  sql.fragment`,`,
37
- )} on conflict on constraint "UserPlatformPermissions_pkey" do nothing`,
40
+ )} on conflict ("platformAdminId", "permission") do nothing`,
38
41
  );
39
42
  };