diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index e5dfd113b..4ed20232d 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -29,7 +29,7 @@ import { elopageWebhook } from '../webhook/elopage' // TODO implement // import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity"; -const DB_VERSION = '0005-admin_tables' +const DB_VERSION = '0006-login_users_collation' const createServer = async (context: any = serverContext): Promise => { // open mysql connection diff --git a/database/entity/0001-init_db/User.ts b/database/entity/0001-init_db/User.ts index 545d4f5c5..b349e2584 100644 --- a/database/entity/0001-init_db/User.ts +++ b/database/entity/0001-init_db/User.ts @@ -2,7 +2,7 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'ty import { Balance } from '../Balance' // Moriz: I do not like the idea of having two user tables -@Entity('state_users') +@Entity('state_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @PrimaryGeneratedColumn('increment', { unsigned: true }) id: number @@ -16,16 +16,28 @@ export class User extends BaseEntity { @Column({ type: 'binary', length: 32, name: 'public_key' }) pubkey: Buffer - @Column({ length: 255, nullable: true, default: null }) + @Column({ length: 255, nullable: true, default: null, collation: 'utf8mb4_unicode_ci' }) email: string - @Column({ name: 'first_name', length: 255, nullable: true, default: null }) + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) firstName: string - @Column({ name: 'last_name', length: 255, nullable: true, default: null }) + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) lastName: string - @Column({ length: 255, nullable: true, default: null }) + @Column({ length: 255, nullable: true, default: null, collation: 'utf8mb4_unicode_ci' }) username: string @Column() diff --git a/database/entity/0002-add_settings/User.ts b/database/entity/0002-add_settings/User.ts index 6f3067c79..78e774489 100644 --- a/database/entity/0002-add_settings/User.ts +++ b/database/entity/0002-add_settings/User.ts @@ -2,7 +2,7 @@ import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany } from 't import { UserSetting } from './UserSetting' // Moriz: I do not like the idea of having two user tables -@Entity('state_users') +@Entity('state_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @PrimaryGeneratedColumn('increment', { unsigned: true }) id: number @@ -16,16 +16,28 @@ export class User extends BaseEntity { @Column({ type: 'binary', length: 32, name: 'public_key' }) pubkey: Buffer - @Column({ length: 255, nullable: true, default: null }) + @Column({ length: 255, nullable: true, default: null, collation: 'utf8mb4_unicode_ci' }) email: string - @Column({ name: 'first_name', length: 255, nullable: true, default: null }) + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) firstName: string - @Column({ name: 'last_name', length: 255, nullable: true, default: null }) + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) lastName: string - @Column({ length: 255, nullable: true, default: null }) + @Column({ length: 255, nullable: true, default: null, collation: 'utf8mb4_unicode_ci' }) username: string @Column() diff --git a/database/entity/0006-login_users_collation/LoginUser.ts b/database/entity/0006-login_users_collation/LoginUser.ts new file mode 100644 index 000000000..e404a3937 --- /dev/null +++ b/database/entity/0006-login_users_collation/LoginUser.ts @@ -0,0 +1,60 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'typeorm' +import { LoginUserBackup } from '../LoginUserBackup' + +// Moriz: I do not like the idea of having two user tables +@Entity('login_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class LoginUser extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ length: 191, unique: true, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ name: 'first_name', length: 150, collation: 'utf8mb4_unicode_ci' }) + firstName: string + + @Column({ name: 'last_name', length: 255, default: '', collation: 'utf8mb4_unicode_ci' }) + lastName: string + + @Column({ length: 255, default: '', collation: 'utf8mb4_unicode_ci' }) + username: string + + @Column({ default: '', collation: 'utf8mb4_unicode_ci' }) + description: string + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'pubkey', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP' }) + createdAt: Date + + @Column({ name: 'email_checked', default: 0 }) + emailChecked: boolean + + @Column({ name: 'passphrase_shown', default: 0 }) + passphraseShown: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci' }) + language: string + + @Column({ default: 0 }) + disabled: boolean + + @Column({ name: 'group_id', default: 0, unsigned: true }) + groupId: number + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @OneToOne(() => LoginUserBackup, (loginUserBackup) => loginUserBackup.loginUser) + loginUserBackup: LoginUserBackup +} diff --git a/database/entity/LoginUser.ts b/database/entity/LoginUser.ts index 034f791cb..b22e1137f 100644 --- a/database/entity/LoginUser.ts +++ b/database/entity/LoginUser.ts @@ -1 +1 @@ -export { LoginUser } from './0003-login_server_tables/LoginUser' +export { LoginUser } from './0006-login_users_collation/LoginUser' diff --git a/database/migrations/0002-add_settings.ts b/database/migrations/0002-add_settings.ts index 5c1b4fbe7..aed4feab4 100644 --- a/database/migrations/0002-add_settings.ts +++ b/database/migrations/0002-add_settings.ts @@ -1,15 +1,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* FIRST MIGRATION +/* MIGRATION TO ADD USER SETTINGS * - * This migration is special since it takes into account that - * the database can be setup already but also may not be. - * Therefore you will find all `CREATE TABLE` statements with - * a `IF NOT EXISTS`, all `INSERT` with an `IGNORE` and in the - * downgrade function all `DROP TABLE` with a `IF EXISTS`. - * This ensures compatibility for existing or non-existing - * databases. + * This migration adds the table `user_setting` in order to store all sorts of user configuration data */ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { diff --git a/database/migrations/0003-login_server_tables.ts b/database/migrations/0003-login_server_tables.ts index d3d720c97..909e63c0b 100644 --- a/database/migrations/0003-login_server_tables.ts +++ b/database/migrations/0003-login_server_tables.ts @@ -1,15 +1,11 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* FIRST MIGRATION +/* MIGRATION TO CREATE THE LOGIN_SERVER TABLES * - * This migration is special since it takes into account that - * the database can be setup already but also may not be. - * Therefore you will find all `CREATE TABLE` statements with - * a `IF NOT EXISTS`, all `INSERT` with an `IGNORE` and in the - * downgrade function all `DROP TABLE` with a `IF EXISTS`. - * This ensures compatibility for existing or non-existing - * databases. + * This migration creates the `login_server` tables in the `community_server` database (`gradido_community`). + * This is done to keep all data in the same place and is to be understood in conjunction with the next migration + * `0004-login_server_data` which will fill the tables with the existing data */ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { diff --git a/database/migrations/0004-login_server_data.ts b/database/migrations/0004-login_server_data.ts index 6d67dcdcb..4a38e016e 100644 --- a/database/migrations/0004-login_server_data.ts +++ b/database/migrations/0004-login_server_data.ts @@ -1,15 +1,15 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* FIRST MIGRATION +/* MIGRATION TO COPY LOGIN_SERVER DATA * - * This migration is special since it takes into account that - * the database can be setup already but also may not be. - * Therefore you will find all `CREATE TABLE` statements with - * a `IF NOT EXISTS`, all `INSERT` with an `IGNORE` and in the - * downgrade function all `DROP TABLE` with a `IF EXISTS`. - * This ensures compatibility for existing or non-existing - * databases. + * This migration copies all existing data from the `login_server` database (`gradido_login`) + * to the `community_server` database (`gradido_community`) in case the login_server database + * is present. + * + * NOTE: This will fail if the two databases are located on different servers. + * Manual export and import of the database will be required then. + * NOTE: This migration does not delete the data when downgrading! */ const LOGIN_SERVER_DB = 'gradido_login' diff --git a/database/migrations/0005-admin_tables.ts b/database/migrations/0005-admin_tables.ts index bd325678f..832008970 100644 --- a/database/migrations/0005-admin_tables.ts +++ b/database/migrations/0005-admin_tables.ts @@ -1,12 +1,6 @@ /* MIGRATION FOR ADMIN INTERFACE * - * This migration is special since it takes into account that - * the database can be setup already but also may not be. - * Therefore you will find all `CREATE TABLE` statements with - * a `IF NOT EXISTS`, all `INSERT` with an `IGNORE` and in the - * downgrade function all `DROP TABLE` with a `IF EXISTS`. - * This ensures compatibility for existing or non-existing - * databases. + * This migration adds the table `login_pending_tasks_admin` to store pending creations */ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { diff --git a/database/migrations/0006-login_users_collation.ts b/database/migrations/0006-login_users_collation.ts new file mode 100644 index 000000000..579bb0a7a --- /dev/null +++ b/database/migrations/0006-login_users_collation.ts @@ -0,0 +1,16 @@ +/* MIGRATION TO ALIGN COLLATIONS + * + * in oder to be able to compare `login_users` with `state_users` + * when the databases default is not `utf8mb4_unicode_ci`, we need + * to also explicitly define it in the table + */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'ALTER TABLE `login_users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `login_users` CONVERT TO CHARACTER SET utf8mb4;') +}