@@ -36,16 +36,16 @@ async function isAllowed({
3636 account_id ?: string ;
3737 name : string ;
3838} ) : Promise < boolean > {
39+ if ( ! account_id ) return false ;
3940 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 ) )
4343 ) ;
4444}
4545
4646async function assertAllowed ( opts ) {
4747 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` ) ;
4949 }
5050}
5151
@@ -161,6 +161,17 @@ export async function set(opts: {
161161 ] ) ;
162162}
163163
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+ */
164175export async function addAdmin ( {
165176 account_id,
166177 name,
@@ -170,21 +181,23 @@ export async function addAdmin({
170181 name : string ;
171182 user : string ;
172183} ) : 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+ ) ;
175187 if ( ! admin_account_id ) {
176188 throw Error ( `no such account '${ user } '` ) ;
177189 }
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+ ) ;
181198 }
182- await assertAllowed ( {
183- account_id,
184- name,
185- } ) ;
186199 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.
188201 await pool . query (
189202 `
190203 UPDATE organizations
@@ -206,6 +219,15 @@ export async function addAdmin({
206219 } ) ;
207220}
208221
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+ */
209231export async function addUser ( {
210232 account_id,
211233 name,
@@ -216,7 +238,7 @@ export async function addUser({
216238 user : string ;
217239} ) : Promise < void > {
218240 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" ) ;
220242 }
221243 const { account_id : user_account_id } = await getAccount ( user ) ;
222244 if ( ! user_account_id ) {
@@ -229,6 +251,14 @@ export async function addUser({
229251 ] ) ;
230252}
231253
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+ */
232262export async function createUser ( {
233263 account_id,
234264 name,
@@ -315,6 +345,9 @@ export async function removeAdmin({
315345 ) ;
316346}
317347
348+ /**
349+ * @param user and account_id or email_address in the accounts table
350+ */
318351export async function getAccount (
319352 user : string ,
320353) : Promise <
0 commit comments