@@ -36,16 +36,16 @@ async function isAllowed({
36
36
account_id ?: string ;
37
37
name : string ;
38
38
} ) : Promise < boolean > {
39
+ if ( ! account_id ) return false ;
39
40
return (
40
- ! ! account_id &&
41
- ( ( await isOrganizationAdmin ( { account_id, name } ) ) ||
42
- ( await isAdmin ( account_id ) ) )
41
+ ( await isOrganizationAdmin ( { account_id, name } ) ) ||
42
+ ( await isAdmin ( account_id ) )
43
43
) ;
44
44
}
45
45
46
46
async function assertAllowed ( opts ) {
47
47
if ( ! ( await isAllowed ( opts ) ) ) {
48
- throw Error ( `user must an admin of the organization` ) ;
48
+ throw Error ( `user must be an admin of the organization` ) ;
49
49
}
50
50
}
51
51
@@ -161,6 +161,17 @@ export async function set(opts: {
161
161
] ) ;
162
162
}
163
163
164
+ /**
165
+ * Promote an existing user to organization admin: adding them to the admin_account_ids list and adding them to be member of the organization.
166
+ * Only site-level admins can perform this operation to prevent privilege escalation.
167
+ * Organization-level admins cannot promote other users to admin status.
168
+ *
169
+ * NOTE: this prevents moving a user from another org to the @name org. Use addUser first, to move a user from one org to another one.
170
+ *
171
+ * @param account_id - The site admin performing the operation
172
+ * @param name - The organization name
173
+ * @param user - The account_id or email address of the user to promote
174
+ */
164
175
export async function addAdmin ( {
165
176
account_id,
166
177
name,
@@ -170,21 +181,23 @@ export async function addAdmin({
170
181
name : string ;
171
182
user : string ;
172
183
} ) : Promise < void > {
173
- const { name : currentOrgName , account_id : admin_account_id } =
174
- await getAccount ( user ) ;
184
+ const { name : usersOrgName , account_id : admin_account_id } = await getAccount (
185
+ user ,
186
+ ) ;
175
187
if ( ! admin_account_id ) {
176
188
throw Error ( `no such account '${ user } '` ) ;
177
189
}
178
- if ( currentOrgName == name ) {
179
- // already an admin of the org
180
- return ;
190
+ if ( usersOrgName != null && usersOrgName !== name ) {
191
+ throw new Error ( `User '${ user } ' is already member of another organization` ) ;
192
+ }
193
+ // await assertAllowed({ account_id, name });
194
+ if ( ! ( await isAdmin ( account_id ) ) ) {
195
+ throw Error (
196
+ "only site admins can make a user an organization admin right now" ,
197
+ ) ;
181
198
}
182
- await assertAllowed ( {
183
- account_id,
184
- name,
185
- } ) ;
186
199
const pool = getPool ( ) ;
187
- // query below takes care to ensure no dups and work in case of null.
200
+ // query below takes care to ensure no dups and works in case of null.
188
201
await pool . query (
189
202
`
190
203
UPDATE organizations
@@ -206,6 +219,15 @@ export async function addAdmin({
206
219
} ) ;
207
220
}
208
221
222
+ /**
223
+ * Add an existing CoCalc user to an organization by setting their org field.
224
+ * Only site-level admins can perform this operation.
225
+ * NOTE: this could move a user from an existing org to another org!
226
+ *
227
+ * @param account_id - The site admin performing the operation
228
+ * @param name - The organization name
229
+ * @param user - The account_id or email address of the user to add
230
+ */
209
231
export async function addUser ( {
210
232
account_id,
211
233
name,
@@ -216,7 +238,7 @@ export async function addUser({
216
238
user : string ;
217
239
} ) : Promise < void > {
218
240
if ( ! ( await isAdmin ( account_id ) ) ) {
219
- throw Error ( "only site admins can move user to an org right now" ) ;
241
+ throw Error ( "only site admins can add/ move a user to an org right now" ) ;
220
242
}
221
243
const { account_id : user_account_id } = await getAccount ( user ) ;
222
244
if ( ! user_account_id ) {
@@ -229,6 +251,14 @@ export async function addUser({
229
251
] ) ;
230
252
}
231
253
254
+ /**
255
+ * Create a new CoCalc account and add it to an organization.
256
+ * Allowed for both site-level admins and organization admins.
257
+ *
258
+ * @param account_id - The admin (site or org) performing the operation
259
+ * @param name - The organization name
260
+ * @returns The account_id of the newly created account
261
+ */
232
262
export async function createUser ( {
233
263
account_id,
234
264
name,
@@ -315,6 +345,9 @@ export async function removeAdmin({
315
345
) ;
316
346
}
317
347
348
+ /**
349
+ * @param user and account_id or email_address in the accounts table
350
+ */
318
351
export async function getAccount (
319
352
user : string ,
320
353
) : Promise <
0 commit comments