From 626dcc1a3d9f95b613d6a2f72fa40319e1db1afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Cutzach?= Date: Mon, 25 Nov 2024 09:42:18 +0100 Subject: [PATCH] wip: ADDING post route --- app/common/User.ts | 2 + app/gen-server/ApiServer.ts | 29 ++++++++++ app/gen-server/entity/ServiceAccount.ts | 17 +++--- app/gen-server/entity/User.ts | 4 +- app/gen-server/lib/homedb/HomeDBManager.ts | 14 +++++ .../lib/homedb/ServiceAccountsManager.ts | 55 +++++++++++++++++++ app/gen-server/lib/homedb/UsersManager.ts | 6 +- .../1730215435023-ServiceAccounts.ts | 42 ++++++-------- test/gen-server/ApiServer.ts | 8 ++- 9 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 app/gen-server/lib/homedb/ServiceAccountsManager.ts diff --git a/app/common/User.ts b/app/common/User.ts index 36d0127c9c..f7eff6b32e 100644 --- a/app/common/User.ts +++ b/app/common/User.ts @@ -10,6 +10,8 @@ export enum UserTypes { 'service' } +export type UserTypesStrings = keyof typeof UserTypes; + /** * Information about a user, including any user attributes. */ diff --git a/app/gen-server/ApiServer.ts b/app/gen-server/ApiServer.ts index 69c3e43b55..315c6def5b 100644 --- a/app/gen-server/ApiServer.ts +++ b/app/gen-server/ApiServer.ts @@ -582,6 +582,35 @@ export class ApiServer { if (data) { this._logDeleteUserEvents(req, data); } return sendReply(req, res, result); })); + + // POST /service-accounts/ + // Creates a new service account attached to the user making the api call. + this._app.post('/api/service-accounts', expressWrap(async (req, res) => { + const userId = getAuthorizedUserId(req); + const serviceAccount: any = await this._dbManager.createServiceAccount(req.body); + return sendOkReply(req, res, { + key:serviceAccount.key, + }); + throw new ApiError(`${userId} post Not implemented yet ;)`, 501); + })); + + // GET /service-accounts/ + // Reads all service accounts attached to the user making the api call. + this._app.get('/api/service-accounts', expressWrap(async (req, res) => { + throw new ApiError('get Not implemented yet ;)', 501); + })); + + // GET /service-accounts/:said + // Reads one particular service account of the user making the api call. + this._app.get('/api/service-accounts/:said', expressWrap(async (req, res) => { + throw new ApiError('get by id Not implemented yet ;)', 501); + })); + + // DELETE /service-accounts/:said + // Deletes one particular service account of the user making the api call. + this._app.delete('/api/service-accounts/:said', expressWrap(async (req, res) => { + throw new ApiError('delete by id Not implemented yet ;)', 501); + })); } private async _getFullUser(req: Request, options: {includePrefs?: boolean} = {}): Promise { diff --git a/app/gen-server/entity/ServiceAccount.ts b/app/gen-server/entity/ServiceAccount.ts index db57aab5e3..0a687822f6 100644 --- a/app/gen-server/entity/ServiceAccount.ts +++ b/app/gen-server/entity/ServiceAccount.ts @@ -1,5 +1,4 @@ -import {BaseEntity, Column, Entity, JoinTable, ManyToOne, PrimaryGeneratedColumn} from "typeorm"; -import { User } from './User'; +import {BaseEntity, Column, Entity, PrimaryGeneratedColumn} from "typeorm"; @Entity({name: 'service_accounts'}) export class ServiceAccount extends BaseEntity { @@ -7,17 +6,15 @@ export class ServiceAccount extends BaseEntity { @PrimaryGeneratedColumn() public id: number; + @Column({type: Number}) + public owner_id: number; + + @Column({type: Number}) + public service_user_id: number; + @Column({type: String}) public description: string; @Column({type: Date, nullable: false}) public endOfLife: string; - - @ManyToOne(type => User) - @JoinTable({ - name: 'service_account_user', - joinColumn: {name: 'service_account_id'}, - inverseJoinColumn: {name: 'user_id'} - }) - public service_account_owner: User; } diff --git a/app/gen-server/entity/User.ts b/app/gen-server/entity/User.ts index 3f1110c4bb..cf2dc21b9d 100644 --- a/app/gen-server/entity/User.ts +++ b/app/gen-server/entity/User.ts @@ -1,5 +1,5 @@ import {UserOptions} from 'app/common/UserAPI'; -import {UserTypes} from 'app/common/User'; +import {UserTypesStrings} from 'app/common/User'; import {nativeValues} from 'app/gen-server/lib/values'; import {makeId} from 'app/server/lib/idUtils'; import {BaseEntity, BeforeInsert, Column, Entity, JoinTable, ManyToMany, OneToMany, OneToOne, @@ -74,7 +74,7 @@ export class User extends BaseEntity { public ref: string; @Column({name: 'type', type: String, default: 'login'}) - public type: UserTypes | null; + public type: UserTypesStrings | null; @BeforeInsert() public async beforeInsert() { diff --git a/app/gen-server/lib/homedb/HomeDBManager.ts b/app/gen-server/lib/homedb/HomeDBManager.ts index 3810e90f7c..76d65a9325 100644 --- a/app/gen-server/lib/homedb/HomeDBManager.ts +++ b/app/gen-server/lib/homedb/HomeDBManager.ts @@ -87,6 +87,7 @@ import { WhereExpressionBuilder } from "typeorm"; import {v4 as uuidv4} from "uuid"; +import { ServiceAccountsManager } from './ServiceAccountsManager'; // Support transactions in Sqlite in async code. This is a monkey patch, affecting // the prototypes of various TypeORM classes. @@ -258,6 +259,7 @@ export type BillingOptions = Partial { + //TODO create new service user in order to have its + //id to insert + const uuid = uuidv4(); + const email = `${uuid}@serviceaccounts.local`; + const serviceUser = await this._homeDb.getUserByLogin(email); + // FIXME use manager.save(entité); + return await manager.createQueryBuilder() + .insert() + .into('service_accounts') + .values({ + ownerId, + serviceUserId: serviceUser.id, + description, + endOfLife, + }) + .execute(); + }); + } +} diff --git a/app/gen-server/lib/homedb/UsersManager.ts b/app/gen-server/lib/homedb/UsersManager.ts index 6a1e8bd386..a335f6eae4 100644 --- a/app/gen-server/lib/homedb/UsersManager.ts +++ b/app/gen-server/lib/homedb/UsersManager.ts @@ -27,6 +27,8 @@ import { Pref } from 'app/gen-server/entity/Pref'; import flatten from 'lodash/flatten'; import { EntityManager } from 'typeorm'; +import { UserTypesStrings } from 'app/common/User'; + // A special user allowed to add/remove the EVERYONE_EMAIL to/from a resource. export const SUPPORT_EMAIL = appSettings.section('access').flag('supportEmail').requireString({ envVar: 'GRIST_SUPPORT_EMAIL', @@ -364,7 +366,7 @@ export class UsersManager { * unset/outdated fields of an existing record. * */ - public async getUserByLogin(email: string, options: GetUserOptions = {}) { + public async getUserByLogin(email: string, options: GetUserOptions = {}, type?: UserTypesStrings) { const {manager: transaction, profile, userOptions} = options; const normalizedEmail = normalizeEmail(email); return await this._runInTransaction(transaction, async manager => { @@ -382,6 +384,8 @@ export class UsersManager { // Special users do not have first time user set so that they don't get redirected to the // welcome page. user.isFirstTimeUser = !NON_LOGIN_EMAILS.includes(normalizedEmail); + // redémarrer lundi ici TODO + user.type = typeof type === 'undefined' ? 'login' : type; login = new Login(); login.email = normalizedEmail; login.user = user; diff --git a/app/gen-server/migration/1730215435023-ServiceAccounts.ts b/app/gen-server/migration/1730215435023-ServiceAccounts.ts index 5b217365a1..eb667f7281 100644 --- a/app/gen-server/migration/1730215435023-ServiceAccounts.ts +++ b/app/gen-server/migration/1730215435023-ServiceAccounts.ts @@ -23,55 +23,48 @@ export class ServiceAccounts1730215435023 implements MigrationInterface { isPrimary: true, }, { - name: 'description', - type: 'varchar' + name: 'owner_id', + type: 'int', }, { - name: 'endOfLife', - type: datetime, - isNullable: false, + name: 'service_user_id', + type: 'int', }, - ], - }) - ); - await queryRunner.createTable( - new Table({ - name: 'service_account_user', - columns: [ { - name: 'service_account_id', - type: 'int', + name: 'description', + type: 'varchar', }, { - name: 'user_id', - type: 'int' + name: 'endOfLife', + type: datetime, + isNullable: false, }, ], }) ); await queryRunner.createForeignKey( - 'service_account_user', + 'service_accounts', new TableForeignKey({ - columnNames: ['service_account_id'], + columnNames: ['service_user_id'], referencedColumnNames: ['id'], - referencedTableName: 'service_accounts', + referencedTableName: 'users', onDelete: 'CASCADE', }) ); await queryRunner.createForeignKey( - 'service_account_user', + 'service_accounts', new TableForeignKey({ - columnNames: ['user_id'], + columnNames: ['owner_id'], referencedColumnNames: ['id'], referencedTableName: 'users', onDelete: 'CASCADE', }) ); await queryRunner.createIndex( - 'service_account_user', + 'service_accounts', new TableIndex({ - name: 'service_account__user', - columnNames: ['service_account_id', 'user_id'], + name: 'service_account__owner', + columnNames: ['service_accounts_owner', 'user_id'], }) ); } @@ -79,6 +72,5 @@ export class ServiceAccounts1730215435023 implements MigrationInterface { public async down(queryRunner: QueryRunner): Promise { await queryRunner.dropColumn('users', 'type'); await queryRunner.dropTable('service_accounts'); - await queryRunner.dropTable('service_account_user'); } } diff --git a/test/gen-server/ApiServer.ts b/test/gen-server/ApiServer.ts index 9253624f92..4a3a5dd1a7 100644 --- a/test/gen-server/ApiServer.ts +++ b/test/gen-server/ApiServer.ts @@ -2350,9 +2350,7 @@ describe('ApiServer', function() { afterEach(async function() { oldEnv.restore(); - // FIXME create the new method to delete services accounts - //const did = await dbManager.testGetId('Curiosity'); - // await dbManager.deleteServices(did as string); + await dbManager.deleteAllServiceAccounts(); }); after(async function() { @@ -2420,6 +2418,10 @@ describe('ApiServer', function() { // it('Endpoint UPDATE /api/service-accounts/{saId}/transfer-to/{userId}', async function() { // }); + + // it('MUSN'T connect as a login user, async function() { + + //}); }); });