diff --git a/apps/envited.ascs.digital/app/dashboard/users/page.tsx b/apps/envited.ascs.digital/app/dashboard/users/page.tsx index 85acae79..060e0cc2 100644 --- a/apps/envited.ascs.digital/app/dashboard/users/page.tsx +++ b/apps/envited.ascs.digital/app/dashboard/users/page.tsx @@ -6,3 +6,5 @@ export default async function Index() { return } + +export const dynamic = 'force-dynamic' diff --git a/apps/envited.ascs.digital/common/database/queries/queries.ts b/apps/envited.ascs.digital/common/database/queries/queries.ts index 466eddfa..c03558de 100644 --- a/apps/envited.ascs.digital/common/database/queries/queries.ts +++ b/apps/envited.ascs.digital/common/database/queries/queries.ts @@ -6,9 +6,10 @@ import { connectDb } from '../database' import * as schema from '../schema' import { fetchTables } from './common' import { maybeUpdatePublishedState, update as updateProfile } from './profiles' -import { getUserById, getUserWithProfileById, getUsersByIssuerId, insertUserTx } from './users' +import { deleteUserById, getUserById, getUserWithProfileById, getUsersByIssuerId, insertUserTx } from './users' const queries = { + deleteUserById, fetchTables, getUserById, getUserWithProfileById, diff --git a/apps/envited.ascs.digital/common/database/queries/users.test.ts b/apps/envited.ascs.digital/common/database/queries/users.test.ts index d4e54d38..97dad846 100644 --- a/apps/envited.ascs.digital/common/database/queries/users.test.ts +++ b/apps/envited.ascs.digital/common/database/queries/users.test.ts @@ -241,6 +241,7 @@ describe('common/database/users', () => { streetAddress: 'Teststraße 1', updatedAt: new Date(), vatId: 'vatId', + isActive: true, }) expect(transaction).toEqual({ id: 'USER_ID', diff --git a/apps/envited.ascs.digital/common/database/queries/users.ts b/apps/envited.ascs.digital/common/database/queries/users.ts index 48e3e797..678c046c 100644 --- a/apps/envited.ascs.digital/common/database/queries/users.ts +++ b/apps/envited.ascs.digital/common/database/queries/users.ts @@ -19,6 +19,13 @@ import { } from '../schema' import { Credential, DatabaseConnection, Issuer, User } from '../types' +export const deleteUserById = (db: DatabaseConnection) => async (id: string) => + db + .update(user) + .set({ isActive: false, updatedAt: new Date() }) + .where(eq(user.id, id)) + .returning({ updatedId: user.id }) + export const getUserById = (db: DatabaseConnection) => async (id: string) => db.select().from(user).where(eq(user.id, id)) @@ -162,6 +169,7 @@ export const _txn = issuerId: id, issuanceDate: new Date(issuanceDate), expirationDate: new Date(expirationDate), + isActive: true, createdAt: new Date(), updatedAt: new Date(), }) diff --git a/apps/envited.ascs.digital/common/database/schema.ts b/apps/envited.ascs.digital/common/database/schema.ts index 657b233c..39ea7a35 100644 --- a/apps/envited.ascs.digital/common/database/schema.ts +++ b/apps/envited.ascs.digital/common/database/schema.ts @@ -21,6 +21,7 @@ export const user = pgTable('user', { addressTypeId: uuid('address_type_id').references(() => addressType.id), issuanceDate: timestamp('issuance_date'), expirationDate: timestamp('expiration_date'), + isActive: boolean('is_active').default(true), createdAt: timestamp('created_at'), updatedAt: timestamp('updated_at'), }) diff --git a/apps/envited.ascs.digital/common/database/types.ts b/apps/envited.ascs.digital/common/database/types.ts index 8f7e7321..ea56002f 100644 --- a/apps/envited.ascs.digital/common/database/types.ts +++ b/apps/envited.ascs.digital/common/database/types.ts @@ -65,6 +65,7 @@ export interface User { issuerId: StringChange issuanceDate: string expirationDate: string + isActive: boolean createdAt: string updatedAt: string } diff --git a/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.test.ts b/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.test.ts new file mode 100644 index 00000000..cfc25ffa --- /dev/null +++ b/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.test.ts @@ -0,0 +1,68 @@ +import * as SUT from './deleteUserById' + +describe('common/serverActions/users/deleteUserById', () => { + it('should return a deleted user as expected', async () => { + // when ... we request a user by id + // then ... it returns a user as expected + const getServerSessionStub = jest.fn().mockResolvedValue({ + user: { + pkh: 'ISSUER_PKH', + }, + }) + const user = { + id: 'USER_PKH', + issuerId: 'ISSUER_PKH', + } + + const expected = { + updatedId: 'USER_PKH', + } + const dbStub = jest.fn().mockResolvedValue({ + getUserById: jest.fn().mockResolvedValue([user]), + deleteUserById: jest.fn().mockResolvedValue([{ updatedId: 'USER_PKH' }]), + }) + + const result = await SUT._deleteUserById({ db: dbStub, getServerSession: getServerSessionStub })('USER_ID') + expect(result).toEqual(expected) + }) + + it('should throw because of missing session', async () => { + // when ... we request a user by id without a session + // then ... it throws as expected + const getServerSessionStub = jest.fn().mockResolvedValue(null) + const user = { + id: 'USER_PKH', + issuerId: 'ISSUER_PKH', + } + const dbStub = jest.fn().mockResolvedValue({ + getUserById: jest.fn().mockResolvedValue([user]), + deleteUserById: jest.fn().mockResolvedValue([{ updatedId: 'USER_PKH' }]), + }) + + await expect( + SUT._deleteUserById({ db: dbStub, getServerSession: getServerSessionStub })('USER_ID'), + ).rejects.toThrow('Something went wrong') + }) + + it('should throw because requester is not allowed to get this resource', async () => { + // when ... we request a user by id, but the requested user is not issued by the requester OR is not their own user + // then ... it throws as expected + const getServerSessionStub = jest.fn().mockResolvedValue({ + user: { + pkh: 'ISSUER_PKH', + }, + }) + const user = { + id: 'USER_PKH', + issuerId: 'FEDERATOR_PKH', + } + const dbStub = jest.fn().mockResolvedValue({ + getUserById: jest.fn().mockResolvedValue([user]), + deleteUserById: jest.fn().mockResolvedValue([{ updatedId: 'USER_PKH' }]), + }) + + await expect( + SUT._deleteUserById({ db: dbStub, getServerSession: getServerSessionStub })('USER_ID'), + ).rejects.toThrow('Something went wrong') + }) +}) diff --git a/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.ts b/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.ts new file mode 100644 index 00000000..042b6a0b --- /dev/null +++ b/apps/envited.ascs.digital/common/serverActions/users/deleteUserById.ts @@ -0,0 +1,38 @@ +import { isNil } from 'ramda' +import { cache } from 'react' + +import { getServerSession } from '../../auth' +import { db } from '../../database/queries' +import { Database } from '../../database/types' +import { userIsIssuedByLoggedInUser } from '../../guards' +import { User } from '../../types' +import { Session } from '../../types/types' +import { badRequestError, error, unauthorizedError } from '../../utils' + +export const _deleteUserById = + ({ db, getServerSession }: { db: Database; getServerSession: () => Promise }) => + async (id: string): Promise => { + try { + const session = await getServerSession() + + if (isNil(session)) { + throw unauthorizedError() + } + + const connection = await db() + const [user] = await connection.getUserById(id) + + if (!userIsIssuedByLoggedInUser(user)(session)) { + throw badRequestError('Incorrect permissions') + } + + const [deletedUser] = await connection.deleteUserById(user.id) + + return deletedUser + } catch (e) { + console.log('error', e) + throw error() + } + } + +export const deleteUserById = cache(_deleteUserById({ db, getServerSession })) diff --git a/apps/envited.ascs.digital/common/types/types.ts b/apps/envited.ascs.digital/common/types/types.ts index bfc89916..c8a2295d 100644 --- a/apps/envited.ascs.digital/common/types/types.ts +++ b/apps/envited.ascs.digital/common/types/types.ts @@ -71,6 +71,7 @@ export interface User { streetAddress: string updatedAt: string vatId?: string + isActive: boolean } export interface Profile { diff --git a/apps/envited.ascs.digital/drizzle/development/0006_complete_caretaker.sql b/apps/envited.ascs.digital/drizzle/development/0006_complete_caretaker.sql new file mode 100644 index 00000000..f40bd8de --- /dev/null +++ b/apps/envited.ascs.digital/drizzle/development/0006_complete_caretaker.sql @@ -0,0 +1 @@ +ALTER TABLE "user" ADD COLUMN "is_active" boolean DEFAULT true; \ No newline at end of file diff --git a/apps/envited.ascs.digital/drizzle/development/meta/0006_snapshot.json b/apps/envited.ascs.digital/drizzle/development/meta/0006_snapshot.json new file mode 100644 index 00000000..7cc0c0b8 --- /dev/null +++ b/apps/envited.ascs.digital/drizzle/development/meta/0006_snapshot.json @@ -0,0 +1,727 @@ +{ + "id": "7c39d3af-9803-4f74-b950-55a3f248f0ab", + "prevId": "20da9d14-e46c-4df0-ac83-582fc97097d0", + "version": "5", + "dialect": "pg", + "tables": { + "addressType": { + "name": "addressType", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "addressType_name_unique": { + "name": "addressType_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "companyCategory": { + "name": "companyCategory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "companyCategory_id_unique": { + "name": "companyCategory_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "companyCategory_name_unique": { + "name": "companyCategory_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "credentialType": { + "name": "credentialType", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "issuer": { + "name": "issuer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "issuer_id_unique": { + "name": "issuer_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "profile": { + "name": "profile", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "street_address": { + "name": "street_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_locality": { + "name": "address_locality", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_country": { + "name": "address_country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone": { + "name": "phone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "offerings": { + "name": "offerings", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "profile_name_user_name_fk": { + "name": "profile_name_user_name_fk", + "tableFrom": "profile", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "name" + ], + "columnsTo": [ + "name" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "profile_name_unique": { + "name": "profile_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "profilesToCompanyCategories": { + "name": "profilesToCompanyCategories", + "schema": "", + "columns": { + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "company_category_id": { + "name": "company_category_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "profilesToCompanyCategories_profile_id_profile_id_fk": { + "name": "profilesToCompanyCategories_profile_id_profile_id_fk", + "tableFrom": "profilesToCompanyCategories", + "tableTo": "profile", + "schemaTo": "public", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "profilesToCompanyCategories_company_category_id_companyCategory_id_fk": { + "name": "profilesToCompanyCategories_company_category_id_companyCategory_id_fk", + "tableFrom": "profilesToCompanyCategories", + "tableTo": "companyCategory", + "schemaTo": "public", + "columnsFrom": [ + "company_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "role": { + "name": "role", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "role_id_unique": { + "name": "role_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_ascs_member": { + "name": "is_ascs_member", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_envited_member": { + "name": "is_envited_member", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "street_address": { + "name": "street_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_locality": { + "name": "address_locality", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_country": { + "name": "address_country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vat_id": { + "name": "vat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "privacy_policy_accepted": { + "name": "privacy_policy_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "articles_of_association_accepted": { + "name": "articles_of_association_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contribution_rules_accepted": { + "name": "contribution_rules_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_type_id": { + "name": "address_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "issuance_date": { + "name": "issuance_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_issuer_id_issuer_id_fk": { + "name": "user_issuer_id_issuer_id_fk", + "tableFrom": "user", + "tableTo": "issuer", + "schemaTo": "public", + "columnsFrom": [ + "issuer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_address_type_id_addressType_id_fk": { + "name": "user_address_type_id_addressType_id_fk", + "tableFrom": "user", + "tableTo": "addressType", + "schemaTo": "public", + "columnsFrom": [ + "address_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_id_unique": { + "name": "user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "user_name_unique": { + "name": "user_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "usersToCredentialTypes": { + "name": "usersToCredentialTypes", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_type_id": { + "name": "credential_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "usersToCredentialTypes_user_id_user_id_fk": { + "name": "usersToCredentialTypes_user_id_user_id_fk", + "tableFrom": "usersToCredentialTypes", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "usersToCredentialTypes_credential_type_id_credentialType_id_fk": { + "name": "usersToCredentialTypes_credential_type_id_credentialType_id_fk", + "tableFrom": "usersToCredentialTypes", + "tableTo": "credentialType", + "schemaTo": "public", + "columnsFrom": [ + "credential_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "usersToRoles": { + "name": "usersToRoles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "usersToRoles_user_id_user_id_fk": { + "name": "usersToRoles_user_id_user_id_fk", + "tableFrom": "usersToRoles", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "usersToRoles_role_id_role_id_fk": { + "name": "usersToRoles_role_id_role_id_fk", + "tableFrom": "usersToRoles", + "tableTo": "role", + "schemaTo": "public", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/envited.ascs.digital/drizzle/development/meta/_journal.json b/apps/envited.ascs.digital/drizzle/development/meta/_journal.json index 773f654f..dc0598fe 100644 --- a/apps/envited.ascs.digital/drizzle/development/meta/_journal.json +++ b/apps/envited.ascs.digital/drizzle/development/meta/_journal.json @@ -43,6 +43,13 @@ "when": 1706620270271, "tag": "0005_solid_charles_xavier", "breakpoints": true + }, + { + "idx": 6, + "version": "5", + "when": 1706625704993, + "tag": "0006_complete_caretaker", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/envited.ascs.digital/drizzle/staging/0005_sour_king_cobra.sql b/apps/envited.ascs.digital/drizzle/staging/0005_sour_king_cobra.sql new file mode 100644 index 00000000..f40bd8de --- /dev/null +++ b/apps/envited.ascs.digital/drizzle/staging/0005_sour_king_cobra.sql @@ -0,0 +1 @@ +ALTER TABLE "user" ADD COLUMN "is_active" boolean DEFAULT true; \ No newline at end of file diff --git a/apps/envited.ascs.digital/drizzle/staging/meta/0005_snapshot.json b/apps/envited.ascs.digital/drizzle/staging/meta/0005_snapshot.json new file mode 100644 index 00000000..8b54e341 --- /dev/null +++ b/apps/envited.ascs.digital/drizzle/staging/meta/0005_snapshot.json @@ -0,0 +1,727 @@ +{ + "id": "557a5fc8-66db-4aa8-bc60-1c6600b02847", + "prevId": "607b4162-c8ff-4fd4-8217-3e17e268d61b", + "version": "5", + "dialect": "pg", + "tables": { + "addressType": { + "name": "addressType", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "addressType_name_unique": { + "name": "addressType_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "companyCategory": { + "name": "companyCategory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "companyCategory_id_unique": { + "name": "companyCategory_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "companyCategory_name_unique": { + "name": "companyCategory_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "credentialType": { + "name": "credentialType", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "issuer": { + "name": "issuer", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "issuer_id_unique": { + "name": "issuer_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "profile": { + "name": "profile", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "street_address": { + "name": "street_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_locality": { + "name": "address_locality", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_country": { + "name": "address_country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone": { + "name": "phone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "offerings": { + "name": "offerings", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "profile_name_user_name_fk": { + "name": "profile_name_user_name_fk", + "tableFrom": "profile", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "name" + ], + "columnsTo": [ + "name" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "profile_name_unique": { + "name": "profile_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "profilesToCompanyCategories": { + "name": "profilesToCompanyCategories", + "schema": "", + "columns": { + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "company_category_id": { + "name": "company_category_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "profilesToCompanyCategories_profile_id_profile_id_fk": { + "name": "profilesToCompanyCategories_profile_id_profile_id_fk", + "tableFrom": "profilesToCompanyCategories", + "tableTo": "profile", + "schemaTo": "public", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "profilesToCompanyCategories_company_category_id_companyCategory_id_fk": { + "name": "profilesToCompanyCategories_company_category_id_companyCategory_id_fk", + "tableFrom": "profilesToCompanyCategories", + "tableTo": "companyCategory", + "schemaTo": "public", + "columnsFrom": [ + "company_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "role": { + "name": "role", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "role_id_unique": { + "name": "role_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_ascs_member": { + "name": "is_ascs_member", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_envited_member": { + "name": "is_envited_member", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "street_address": { + "name": "street_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_locality": { + "name": "address_locality", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_country": { + "name": "address_country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vat_id": { + "name": "vat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "privacy_policy_accepted": { + "name": "privacy_policy_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "articles_of_association_accepted": { + "name": "articles_of_association_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contribution_rules_accepted": { + "name": "contribution_rules_accepted", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_type_id": { + "name": "address_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "issuance_date": { + "name": "issuance_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_issuer_id_issuer_id_fk": { + "name": "user_issuer_id_issuer_id_fk", + "tableFrom": "user", + "tableTo": "issuer", + "schemaTo": "public", + "columnsFrom": [ + "issuer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_address_type_id_addressType_id_fk": { + "name": "user_address_type_id_addressType_id_fk", + "tableFrom": "user", + "tableTo": "addressType", + "schemaTo": "public", + "columnsFrom": [ + "address_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_id_unique": { + "name": "user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "user_name_unique": { + "name": "user_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "usersToCredentialTypes": { + "name": "usersToCredentialTypes", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_type_id": { + "name": "credential_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "usersToCredentialTypes_user_id_user_id_fk": { + "name": "usersToCredentialTypes_user_id_user_id_fk", + "tableFrom": "usersToCredentialTypes", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "usersToCredentialTypes_credential_type_id_credentialType_id_fk": { + "name": "usersToCredentialTypes_credential_type_id_credentialType_id_fk", + "tableFrom": "usersToCredentialTypes", + "tableTo": "credentialType", + "schemaTo": "public", + "columnsFrom": [ + "credential_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "usersToRoles": { + "name": "usersToRoles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "usersToRoles_user_id_user_id_fk": { + "name": "usersToRoles_user_id_user_id_fk", + "tableFrom": "usersToRoles", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "usersToRoles_role_id_role_id_fk": { + "name": "usersToRoles_role_id_role_id_fk", + "tableFrom": "usersToRoles", + "tableTo": "role", + "schemaTo": "public", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/envited.ascs.digital/drizzle/staging/meta/_journal.json b/apps/envited.ascs.digital/drizzle/staging/meta/_journal.json index df600ad3..a8d95c24 100644 --- a/apps/envited.ascs.digital/drizzle/staging/meta/_journal.json +++ b/apps/envited.ascs.digital/drizzle/staging/meta/_journal.json @@ -36,6 +36,13 @@ "when": 1706620277155, "tag": "0004_dear_scarlet_spider", "breakpoints": true + }, + { + "idx": 5, + "version": "5", + "when": 1706625722525, + "tag": "0005_sour_king_cobra", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/envited.ascs.digital/modules/Users/Users.actions.ts b/apps/envited.ascs.digital/modules/Users/Users.actions.ts new file mode 100644 index 00000000..de593afb --- /dev/null +++ b/apps/envited.ascs.digital/modules/Users/Users.actions.ts @@ -0,0 +1,17 @@ +'use server' + +import { revalidatePath } from 'next/cache' + +import { deleteUserById } from '../../common/serverActions/users/deleteUserById' +import { error } from '../../common/utils' + +export async function deleteUser(id: string) { + try { + await deleteUserById(id) + + revalidatePath('/dashboard/users') + } catch (e) { + console.log('error', e) + throw error() + } +} diff --git a/apps/envited.ascs.digital/modules/Users/Users.tsx b/apps/envited.ascs.digital/modules/Users/Users.tsx index 1575d7b3..be40a331 100644 --- a/apps/envited.ascs.digital/modules/Users/Users.tsx +++ b/apps/envited.ascs.digital/modules/Users/Users.tsx @@ -1,18 +1,22 @@ 'use client' import { Card, Heading, Table, TableBody, TableCell, TableHeader, TableRow } from '@envited-marketplace/design-system' +import { TrashIcon } from '@heroicons/react/24/outline' import { map } from 'ramda' import React, { FC } from 'react' import { useTranslation } from '../../common/i18n' import { User } from '../../common/types/types' +import { deleteUser } from './Users.actions' interface UsersProps { - users: Partial[] + users: User[] } export const Users: FC = ({ users }) => { const { t } = useTranslation('Users') + const deleteUserWithId = (id: string) => deleteUser.bind(null, id) + return ( {t('[Heading] users')} @@ -28,14 +32,41 @@ export const Users: FC = ({ users }) => { {t('[Heading] email')} + + {t('[Heading] status')} + + - {map(({ id, name, email }: Partial) => ( + {map(({ id, name, email, isActive }: User) => ( {id} {name} {email} + + + {t(isActive ? '[Label] active' : '[Label] inactive')} + + + + {isActive ? ( + + + {t('[Button] deactivate')} + + + + ) : ( + <>> + )} + ))(users)} diff --git a/apps/envited.ascs.digital/modules/Users/locales/de_DE.json b/apps/envited.ascs.digital/modules/Users/locales/de_DE.json index 0113dff9..97fa20cf 100644 --- a/apps/envited.ascs.digital/modules/Users/locales/de_DE.json +++ b/apps/envited.ascs.digital/modules/Users/locales/de_DE.json @@ -3,5 +3,8 @@ "[Heading] name": "Name", "[Heading] email": "Email", "[Heading] did": "DID", - "[Heading] actions": "Actions" + "[Heading] status": "Status", + "[Button] deactivate": "Deactivate", + "[Label] active": "Active", + "[Label] inactive": "Inactive" } diff --git a/apps/envited.ascs.digital/modules/Users/locales/en_GB.json b/apps/envited.ascs.digital/modules/Users/locales/en_GB.json index 0113dff9..97fa20cf 100644 --- a/apps/envited.ascs.digital/modules/Users/locales/en_GB.json +++ b/apps/envited.ascs.digital/modules/Users/locales/en_GB.json @@ -3,5 +3,8 @@ "[Heading] name": "Name", "[Heading] email": "Email", "[Heading] did": "DID", - "[Heading] actions": "Actions" + "[Heading] status": "Status", + "[Button] deactivate": "Deactivate", + "[Label] active": "Active", + "[Label] inactive": "Inactive" }