From 145989e2848af0a9c32e32c99327d0616d1bf5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Apr 2022 14:43:25 +0200 Subject: [PATCH 01/95] Replace notActivated by isEmailChecked --- admin/src/graphql/searchUsers.js | 4 ++-- admin/src/pages/Creation.spec.js | 8 ++++---- admin/src/pages/Creation.vue | 2 +- admin/src/pages/UserSearch.spec.js | 12 ++++++------ admin/src/pages/UserSearch.vue | 2 +- backend/src/graphql/arg/SearchUsersArgs.ts | 2 +- backend/src/graphql/resolver/AdminResolver.ts | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index e28508d1b..889b01972 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -5,14 +5,14 @@ export const searchUsers = gql` $searchText: String! $currentPage: Int $pageSize: Int - $notActivated: Boolean + $isEmailChecked: Boolean $isDeleted: Boolean ) { searchUsers( searchText: $searchText currentPage: $currentPage pageSize: $pageSize - notActivated: $notActivated + isEmailChecked: $isEmailChecked isDeleted: $isDeleted ) { userCount diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index 204c35817..58c7e3796 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -71,8 +71,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, + isEmailChecked: true, isDeleted: false, - notActivated: false, }, }), ) @@ -271,8 +271,8 @@ describe('Creation', () => { searchText: 'XX', currentPage: 1, pageSize: 25, + isEmailChecked: true, isDeleted: false, - notActivated: false, }, }), ) @@ -288,8 +288,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, + isEmailChecked: true, isDeleted: false, - notActivated: false, }, }), ) @@ -305,8 +305,8 @@ describe('Creation', () => { searchText: '', currentPage: 2, pageSize: 25, + isEmailChecked: true, isDeleted: false, - notActivated: false, }, }), ) diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index e5b93350f..ab4993beb 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -102,7 +102,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - notActivated: false, + isEmailChecked: true, isDeleted: false, }, fetchPolicy: 'network-only', diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index 0b98d4d11..c2bceaade 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -82,7 +82,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - notActivated: null, + isEmailChecked: null, isDeleted: null, }, }), @@ -101,7 +101,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - notActivated: true, + isEmailChecked: false, isDeleted: null, }, }), @@ -121,7 +121,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - notActivated: null, + isEmailChecked: null, isDeleted: true, }, }), @@ -141,7 +141,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 2, pageSize: 25, - notActivated: null, + isEmailChecked: null, isDeleted: null, }, }), @@ -161,7 +161,7 @@ describe('UserSearch', () => { searchText: 'search string', currentPage: 1, pageSize: 25, - notActivated: null, + isEmailChecked: null, isDeleted: null, }, }), @@ -178,7 +178,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - notActivated: null, + isEmailChecked: null, isDeleted: null, }, }), diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index b2737bae6..718656b9f 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -85,7 +85,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - notActivated: this.filterCheckedEmails, + isEmailChecked: !this.filterCheckedEmails, // Wolle: has this boolean really to be negated as well? isDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts index 2a94d8998..72fdf0499 100644 --- a/backend/src/graphql/arg/SearchUsersArgs.ts +++ b/backend/src/graphql/arg/SearchUsersArgs.ts @@ -12,7 +12,7 @@ export default class SearchUsersArgs { pageSize?: number @Field(() => Boolean, { nullable: true }) - notActivated?: boolean | null + isEmailChecked?: boolean | null @Field(() => Boolean, { nullable: true }) isDeleted?: boolean | null diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 7ca3460ee..62e64f7f5 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -56,15 +56,15 @@ export class AdminResolver { searchText, currentPage = 1, pageSize = 25, - notActivated = null, + isEmailChecked = null, isDeleted = null, }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) const filterCriteria: ObjectLiteral[] = [] - if (notActivated !== null) { - filterCriteria.push({ emailChecked: !notActivated }) + if (isEmailChecked !== null) { + filterCriteria.push({ emailChecked: isEmailChecked }) } if (isDeleted !== null) { From 3344dfc771e641498ec0046d46d1cc7984087b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 19 Apr 2022 15:13:59 +0200 Subject: [PATCH 02/95] Fix admin tests --- admin/src/pages/UserSearch.spec.js | 2 +- admin/src/pages/UserSearch.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index c2bceaade..0f11a0435 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -101,7 +101,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: false, + isEmailChecked: true, isDeleted: null, }, }), diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index 718656b9f..f1c222a78 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -85,7 +85,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - isEmailChecked: !this.filterCheckedEmails, // Wolle: has this boolean really to be negated as well? + isEmailChecked: this.filterCheckedEmails, isDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', From 03e1624c11394d98a2804e65384c8bc39d56d9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Apr 2022 08:48:13 +0200 Subject: [PATCH 03/95] Rename isEmailChecked to emailChecked --- admin/src/graphql/searchUsers.js | 4 ++-- admin/src/pages/Creation.spec.js | 8 ++++---- admin/src/pages/Creation.vue | 2 +- admin/src/pages/UserSearch.spec.js | 12 ++++++------ admin/src/pages/UserSearch.vue | 2 +- backend/src/graphql/arg/SearchUsersArgs.ts | 2 +- backend/src/graphql/resolver/AdminResolver.ts | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index 889b01972..ca7bc4718 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -5,14 +5,14 @@ export const searchUsers = gql` $searchText: String! $currentPage: Int $pageSize: Int - $isEmailChecked: Boolean + $emailChecked: Boolean $isDeleted: Boolean ) { searchUsers( searchText: $searchText currentPage: $currentPage pageSize: $pageSize - isEmailChecked: $isEmailChecked + emailChecked: $emailChecked isDeleted: $isDeleted ) { userCount diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index 58c7e3796..1f172139b 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -71,7 +71,7 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: true, + emailChecked: true, isDeleted: false, }, }), @@ -271,7 +271,7 @@ describe('Creation', () => { searchText: 'XX', currentPage: 1, pageSize: 25, - isEmailChecked: true, + emailChecked: true, isDeleted: false, }, }), @@ -288,7 +288,7 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: true, + emailChecked: true, isDeleted: false, }, }), @@ -305,7 +305,7 @@ describe('Creation', () => { searchText: '', currentPage: 2, pageSize: 25, - isEmailChecked: true, + emailChecked: true, isDeleted: false, }, }), diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index ab4993beb..6657b5915 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -102,7 +102,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - isEmailChecked: true, + emailChecked: true, isDeleted: false, }, fetchPolicy: 'network-only', diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index 0f11a0435..18950c46a 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -82,7 +82,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: null, + emailChecked: null, isDeleted: null, }, }), @@ -101,7 +101,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: true, + emailChecked: true, isDeleted: null, }, }), @@ -121,7 +121,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: null, + emailChecked: null, isDeleted: true, }, }), @@ -141,7 +141,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 2, pageSize: 25, - isEmailChecked: null, + emailChecked: null, isDeleted: null, }, }), @@ -161,7 +161,7 @@ describe('UserSearch', () => { searchText: 'search string', currentPage: 1, pageSize: 25, - isEmailChecked: null, + emailChecked: null, isDeleted: null, }, }), @@ -178,7 +178,7 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - isEmailChecked: null, + emailChecked: null, isDeleted: null, }, }), diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index f1c222a78..06abd25aa 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -85,7 +85,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - isEmailChecked: this.filterCheckedEmails, + emailChecked: this.filterCheckedEmails, isDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts index 72fdf0499..677d1958b 100644 --- a/backend/src/graphql/arg/SearchUsersArgs.ts +++ b/backend/src/graphql/arg/SearchUsersArgs.ts @@ -12,7 +12,7 @@ export default class SearchUsersArgs { pageSize?: number @Field(() => Boolean, { nullable: true }) - isEmailChecked?: boolean | null + emailChecked?: boolean | null @Field(() => Boolean, { nullable: true }) isDeleted?: boolean | null diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 62e64f7f5..2801a2b81 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -56,15 +56,15 @@ export class AdminResolver { searchText, currentPage = 1, pageSize = 25, - isEmailChecked = null, + emailChecked = null, isDeleted = null, }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) const filterCriteria: ObjectLiteral[] = [] - if (isEmailChecked !== null) { - filterCriteria.push({ emailChecked: isEmailChecked }) + if (emailChecked !== null) { + filterCriteria.push({ emailChecked: emailChecked }) } if (isDeleted !== null) { From e8aba864309665c5842c24cf95a94856e1aceb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Wed, 20 Apr 2022 08:53:12 +0200 Subject: [PATCH 04/95] Rename isDeleted to deletedAt --- admin/src/graphql/searchUsers.js | 4 ++-- admin/src/pages/Creation.spec.js | 8 ++++---- admin/src/pages/Creation.vue | 2 +- admin/src/pages/UserSearch.spec.js | 12 ++++++------ admin/src/pages/UserSearch.vue | 2 +- backend/src/graphql/arg/SearchUsersArgs.ts | 2 +- backend/src/graphql/resolver/AdminResolver.ts | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index ca7bc4718..fc81f3f1b 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -6,14 +6,14 @@ export const searchUsers = gql` $currentPage: Int $pageSize: Int $emailChecked: Boolean - $isDeleted: Boolean + $deletedAt: Boolean ) { searchUsers( searchText: $searchText currentPage: $currentPage pageSize: $pageSize emailChecked: $emailChecked - isDeleted: $isDeleted + deletedAt: $deletedAt ) { userCount userList { diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index 1f172139b..e60625dd2 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -72,7 +72,7 @@ describe('Creation', () => { currentPage: 1, pageSize: 25, emailChecked: true, - isDeleted: false, + deletedAt: false, }, }), ) @@ -272,7 +272,7 @@ describe('Creation', () => { currentPage: 1, pageSize: 25, emailChecked: true, - isDeleted: false, + deletedAt: false, }, }), ) @@ -289,7 +289,7 @@ describe('Creation', () => { currentPage: 1, pageSize: 25, emailChecked: true, - isDeleted: false, + deletedAt: false, }, }), ) @@ -306,7 +306,7 @@ describe('Creation', () => { currentPage: 2, pageSize: 25, emailChecked: true, - isDeleted: false, + deletedAt: false, }, }), ) diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index 6657b5915..30900a468 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -103,7 +103,7 @@ export default { currentPage: this.currentPage, pageSize: this.perPage, emailChecked: true, - isDeleted: false, + deletedAt: false, }, fetchPolicy: 'network-only', }) diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index 18950c46a..907cbd7e0 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -83,7 +83,7 @@ describe('UserSearch', () => { currentPage: 1, pageSize: 25, emailChecked: null, - isDeleted: null, + deletedAt: null, }, }), ) @@ -102,7 +102,7 @@ describe('UserSearch', () => { currentPage: 1, pageSize: 25, emailChecked: true, - isDeleted: null, + deletedAt: null, }, }), ) @@ -122,7 +122,7 @@ describe('UserSearch', () => { currentPage: 1, pageSize: 25, emailChecked: null, - isDeleted: true, + deletedAt: true, }, }), ) @@ -142,7 +142,7 @@ describe('UserSearch', () => { currentPage: 2, pageSize: 25, emailChecked: null, - isDeleted: null, + deletedAt: null, }, }), ) @@ -162,7 +162,7 @@ describe('UserSearch', () => { currentPage: 1, pageSize: 25, emailChecked: null, - isDeleted: null, + deletedAt: null, }, }), ) @@ -179,7 +179,7 @@ describe('UserSearch', () => { currentPage: 1, pageSize: 25, emailChecked: null, - isDeleted: null, + deletedAt: null, }, }), ) diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index 06abd25aa..e5f584a25 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -86,7 +86,7 @@ export default { currentPage: this.currentPage, pageSize: this.perPage, emailChecked: this.filterCheckedEmails, - isDeleted: this.filterDeletedUser, + deletedAt: this.filterDeletedUser, }, fetchPolicy: 'no-cache', }) diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts index 677d1958b..103152bac 100644 --- a/backend/src/graphql/arg/SearchUsersArgs.ts +++ b/backend/src/graphql/arg/SearchUsersArgs.ts @@ -15,5 +15,5 @@ export default class SearchUsersArgs { emailChecked?: boolean | null @Field(() => Boolean, { nullable: true }) - isDeleted?: boolean | null + deletedAt?: boolean | null } diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 2801a2b81..495e6fb3f 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -57,7 +57,7 @@ export class AdminResolver { currentPage = 1, pageSize = 25, emailChecked = null, - isDeleted = null, + deletedAt = null, }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) @@ -67,8 +67,8 @@ export class AdminResolver { filterCriteria.push({ emailChecked: emailChecked }) } - if (isDeleted !== null) { - filterCriteria.push({ deletedAt: isDeleted ? Not(IsNull()) : IsNull() }) + if (deletedAt !== null) { + filterCriteria.push({ deletedAt: deletedAt ? Not(IsNull()) : IsNull() }) } const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt'] From deb1d457e1a2f60815d713cfb5c7bf76cf843881 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 10:32:33 +0200 Subject: [PATCH 05/95] migration adds is_admin column to users --- database/migrations/0034-drop_server_user_table.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 database/migrations/0034-drop_server_user_table.ts diff --git a/database/migrations/0034-drop_server_user_table.ts b/database/migrations/0034-drop_server_user_table.ts new file mode 100644 index 000000000..2e0a789ac --- /dev/null +++ b/database/migrations/0034-drop_server_user_table.ts @@ -0,0 +1,13 @@ +/* MIGRATION DROP server_users TABLE +add isAdmin COLUMN to users TABLE */ + +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `users` ADD COLUMN `is_admin` boolean DEFAULT false AFTER `language`;') +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `users` DROP COLUMN `is_admin`;') +} From 58ab92ff63ba88071a02aaf807eff54044f096a1 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:11:40 +0200 Subject: [PATCH 06/95] drop server users --- .../migrations/0034-drop_server_user_table.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/database/migrations/0034-drop_server_user_table.ts b/database/migrations/0034-drop_server_user_table.ts index 2e0a789ac..914c75457 100644 --- a/database/migrations/0034-drop_server_user_table.ts +++ b/database/migrations/0034-drop_server_user_table.ts @@ -6,8 +6,32 @@ add isAdmin COLUMN to users TABLE */ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { await queryFn('ALTER TABLE `users` ADD COLUMN `is_admin` boolean DEFAULT false AFTER `language`;') + + await queryFn( + 'UPDATE `users` SET `is_admin` = true WHERE `email` IN (SELECT `email` FROM `server_users`);', + ) + + await queryFn('DROP TABLE `server_users`;') } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(` + CREATE TABLE IF NOT EXISTS \`server_users\` ( + \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, + \`username\` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + \`password\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + \`email\` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + \`role\` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'admin', + \`activated\` tinyint(4) NOT NULL DEFAULT '0', + \`last_login\` datetime DEFAULT NULL, + \`created\` datetime NOT NULL, + \`modified\` datetime NOT NULL, + PRIMARY KEY (\`id\`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) + + await queryFn( + 'INSERT INTO `server_users` (`email`, `username`, `password`, `created`, `modified`) SELECT `email`, `first_name`, `password`, `created`, `created` FROM `users` WHERE `is_admin` = true;', + ) + await queryFn('ALTER TABLE `users` DROP COLUMN `is_admin`;') } From ca4a92d321d804dda4c8c4a79b0bea716616ff1b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:19:02 +0200 Subject: [PATCH 07/95] add isAdmin entity to user db model --- .../0034-drop_server_user_table/User.ts | 81 +++++++++++++++++++ database/entity/User.ts | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 database/entity/0034-drop_server_user_table/User.ts diff --git a/database/entity/0034-drop_server_user_table/User.ts b/database/entity/0034-drop_server_user_table/User.ts new file mode 100644 index 000000000..9192b92ff --- /dev/null +++ b/database/entity/0034-drop_server_user_table/User.ts @@ -0,0 +1,81 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + OneToMany, + DeleteDateColumn, +} from 'typeorm' +import { UserSetting } from '../UserSetting' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @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, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'bool', nullable: false, default: false }) + isAdmin: boolean + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string + + @OneToMany(() => UserSetting, (userSetting) => userSetting.user) + settings: UserSetting[] +} diff --git a/database/entity/User.ts b/database/entity/User.ts index 35dfb7bbe..4cd68174c 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0033-add_referrer_id/User' +export { User } from './0034-drop_server_user_table/User' From 5c6aa5d4ce715911dd60128ac6448b4c807e9c6e Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:20:28 +0200 Subject: [PATCH 08/95] new db version for isAdmin in user db model --- backend/src/config/index.ts | 2 +- backend/src/util/communityUser.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 91f450369..4bf550038 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0033-add_referrer_id', + DB_VERSION: '0034-drop_server_user_table', DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0 CONFIG_VERSION: { DEFAULT: 'DEFAULT', diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index 33ac2fad2..8b75b37a1 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -17,6 +17,7 @@ const communityDbUser: dbUser = { createdAt: new Date(), emailChecked: false, language: '', + isAdmin: false, publisherId: 0, passphrase: '', settings: [], From 64859a71f44457afc97b31f2fbe225451dedb90b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:27:09 +0200 Subject: [PATCH 09/95] use isAdmin on user to determine if user is admin --- backend/src/graphql/model/User.ts | 8 ++++---- backend/src/graphql/resolver/UserResolver.ts | 10 ---------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 1a187a38f..1949592c0 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -14,8 +14,8 @@ export class User { this.emailChecked = user.emailChecked this.language = user.language this.publisherId = user.publisherId + this.isAdmin = user.isAdmin // TODO - this.isAdmin = null this.coinanimation = null this.klickTipp = null this.hasElopage = null @@ -58,11 +58,11 @@ export class User { // `passphrase` text COLLATE utf8mb4_unicode_ci DEFAULT NULL, + @Field(() => Boolean) + isAdmin: boolean + // TODO this is a bit inconsistent with what we query from the database // therefore all those fields are now nullable with default value null - @Field(() => Boolean, { nullable: true }) - isAdmin: boolean | null - @Field(() => Boolean, { nullable: true }) coinanimation: boolean | null diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 137c09622..7685268b4 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -19,9 +19,7 @@ import { sendResetPasswordEmail as sendResetPasswordEmailMailer } from '@/mailer import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' -import { ROLE_ADMIN } from '@/auth/ROLES' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { ServerUser } from '@entity/ServerUser' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -207,7 +205,6 @@ export class UserResolver { }) user.coinanimation = coinanimation - user.isAdmin = context.role === ROLE_ADMIN return user } @@ -243,9 +240,6 @@ export class UserResolver { } const user = new User(dbUser) - // user.email = email - // user.pubkey = dbUser.pubKey.toString('hex') - user.language = dbUser.language // Elopage Status & Stored PublisherId user.hasElopage = await this.hasElopage({ ...context, user: dbUser }) @@ -266,10 +260,6 @@ export class UserResolver { }) user.coinanimation = coinanimation - // context.role is not set to the actual role yet on login - const countServerUsers = await ServerUser.count({ email: user.email }) - user.isAdmin = countServerUsers > 0 - context.setHeaders.push({ key: 'token', value: encode(dbUser.pubKey), From 8ca72beac8cdbd5ebf112f90d09652e398ad41c5 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:30:29 +0200 Subject: [PATCH 10/95] use isAdmin of user to determine user role --- backend/src/graphql/directive/isAuthorized.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 84756c45a..065c01957 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -8,7 +8,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { getCustomRepository } from '@dbTools/typeorm' import { UserRepository } from '@repository/User' import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS' -import { ServerUser } from '@entity/ServerUser' const isAuthorized: AuthChecker = async ({ context }, rights) => { context.role = ROLE_UNAUTHORIZED // unauthorized user @@ -36,8 +35,7 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { try { const user = await userRepository.findByPubkeyHex(context.pubKey) context.user = user - const countServerUsers = await ServerUser.count({ email: user.email }) - context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER + context.role = user.isAdmin ? ROLE_ADMIN : ROLE_USER } catch { // in case the database query fails (user deleted) throw new Error('401 Unauthorized') From 9136c4596dad00460523b789718ede5871fa80ab Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:32:30 +0200 Subject: [PATCH 11/95] remove server user entity --- database/entity/ServerUser.ts | 1 - database/entity/index.ts | 2 -- 2 files changed, 3 deletions(-) delete mode 100644 database/entity/ServerUser.ts diff --git a/database/entity/ServerUser.ts b/database/entity/ServerUser.ts deleted file mode 100644 index 495513823..000000000 --- a/database/entity/ServerUser.ts +++ /dev/null @@ -1 +0,0 @@ -export { ServerUser } from './0001-init_db/ServerUser' diff --git a/database/entity/index.ts b/database/entity/index.ts index cb6f56ab0..542333755 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -1,7 +1,6 @@ import { LoginElopageBuys } from './LoginElopageBuys' import { LoginEmailOptIn } from './LoginEmailOptIn' import { Migration } from './Migration' -import { ServerUser } from './ServerUser' import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' import { User } from './User' @@ -13,7 +12,6 @@ export const entities = [ LoginElopageBuys, LoginEmailOptIn, Migration, - ServerUser, Transaction, TransactionLink, User, From c9701574f38cf28d3ad26a3a37b02dd0bafa82df Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 20 Apr 2022 11:44:34 +0200 Subject: [PATCH 12/95] seed with isAdmin, test user resolver with isAdmin --- .../src/graphql/resolver/UserResolver.test.ts | 1 + backend/src/seeds/factory/user.ts | 23 ++++--------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 07b8e59e2..b9e230afe 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -100,6 +100,7 @@ describe('UserResolver', () => { emailChecked: false, passphrase: expect.any(String), language: 'de', + isAdmin: false, deletedAt: null, publisherId: 1234, referrerId: null, diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index ff4c1d6c9..373a3da4f 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -1,7 +1,6 @@ import { createUser, setPassword } from '@/seeds/graphql/mutations' import { User } from '@entity/User' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' -import { ServerUser } from '@entity/ServerUser' import { UserInterface } from '@/seeds/users/UserInterface' import { ApolloServerTestClient } from 'apollo-server-testing' @@ -29,23 +28,9 @@ export const userFactory = async ( // get user from database const dbUser = await User.findOneOrFail({ id }) - if (user.createdAt || user.deletedAt) { - if (user.createdAt) dbUser.createdAt = user.createdAt - if (user.deletedAt) dbUser.deletedAt = user.deletedAt - await dbUser.save() - } - - if (user.isAdmin) { - const admin = new ServerUser() - admin.username = dbUser.firstName - admin.password = 'please_refactor' - admin.email = dbUser.email - admin.role = 'admin' - admin.activated = 1 - admin.lastLogin = new Date() - admin.created = dbUser.createdAt - admin.modified = dbUser.createdAt - await admin.save() - } + if (user.createdAt) dbUser.createdAt = user.createdAt + if (user.deletedAt) dbUser.deletedAt = user.deletedAt + if (user.isAdmin) dbUser.isAdmin = user.isAdmin + await dbUser.save() } } From 621786c91d7615774bc7d1a955c0304c54e86a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Apr 2022 07:51:00 +0200 Subject: [PATCH 13/95] Rename after suggestion emailChecked withActivated and deletedAt to withDeleted --- admin/src/graphql/searchUsers.js | 12 +++++----- admin/src/pages/Creation.spec.js | 16 ++++++------- admin/src/pages/Creation.vue | 4 ++-- admin/src/pages/UserSearch.spec.js | 24 +++++++++---------- admin/src/pages/UserSearch.vue | 4 ++-- backend/src/graphql/arg/SearchUsersArgs.ts | 4 ++-- backend/src/graphql/resolver/AdminResolver.ts | 12 +++++----- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index fc81f3f1b..706927eb1 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -5,15 +5,15 @@ export const searchUsers = gql` $searchText: String! $currentPage: Int $pageSize: Int - $emailChecked: Boolean - $deletedAt: Boolean + $withActivated: Boolean + $withDeleted: Boolean ) { searchUsers( searchText: $searchText currentPage: $currentPage pageSize: $pageSize - emailChecked: $emailChecked - deletedAt: $deletedAt + withActivated: $withActivated + withDeleted: $withDeleted ) { userCount userList { @@ -22,10 +22,10 @@ export const searchUsers = gql` lastName email creation - emailChecked hasElopage emailConfirmationSend - deletedAt + withActivated + withDeleted } } } diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index e60625dd2..d1d6f0f2e 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -71,8 +71,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: true, - deletedAt: false, + withActivated: true, + withDeleted: false, }, }), ) @@ -271,8 +271,8 @@ describe('Creation', () => { searchText: 'XX', currentPage: 1, pageSize: 25, - emailChecked: true, - deletedAt: false, + withActivated: true, + withDeleted: false, }, }), ) @@ -288,8 +288,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: true, - deletedAt: false, + withActivated: true, + withDeleted: false, }, }), ) @@ -305,8 +305,8 @@ describe('Creation', () => { searchText: '', currentPage: 2, pageSize: 25, - emailChecked: true, - deletedAt: false, + withActivated: true, + withDeleted: false, }, }), ) diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index 30900a468..76d6077f5 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -102,8 +102,8 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - emailChecked: true, - deletedAt: false, + withActivated: true, + withDeleted: false, }, fetchPolicy: 'network-only', }) diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index 907cbd7e0..602852608 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -82,8 +82,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: null, - deletedAt: null, + withActivated: null, + withDeleted: null, }, }), ) @@ -101,8 +101,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: true, - deletedAt: null, + withActivated: true, + withDeleted: null, }, }), ) @@ -121,8 +121,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: null, - deletedAt: true, + withActivated: null, + withDeleted: true, }, }), ) @@ -141,8 +141,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 2, pageSize: 25, - emailChecked: null, - deletedAt: null, + withActivated: null, + withDeleted: null, }, }), ) @@ -161,8 +161,8 @@ describe('UserSearch', () => { searchText: 'search string', currentPage: 1, pageSize: 25, - emailChecked: null, - deletedAt: null, + withActivated: null, + withDeleted: null, }, }), ) @@ -178,8 +178,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - emailChecked: null, - deletedAt: null, + withActivated: null, + withDeleted: null, }, }), ) diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index e5f584a25..f0bf60ae1 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -85,8 +85,8 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - emailChecked: this.filterCheckedEmails, - deletedAt: this.filterDeletedUser, + withActivated: this.filterCheckedEmails, + withDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', }) diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts index 103152bac..fab17e527 100644 --- a/backend/src/graphql/arg/SearchUsersArgs.ts +++ b/backend/src/graphql/arg/SearchUsersArgs.ts @@ -12,8 +12,8 @@ export default class SearchUsersArgs { pageSize?: number @Field(() => Boolean, { nullable: true }) - emailChecked?: boolean | null + withActivated?: boolean | null @Field(() => Boolean, { nullable: true }) - deletedAt?: boolean | null + withDeleted?: boolean | null } diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 495e6fb3f..bdb078ad1 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -56,19 +56,19 @@ export class AdminResolver { searchText, currentPage = 1, pageSize = 25, - emailChecked = null, - deletedAt = null, + withActivated = null, + withDeleted = null, }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) const filterCriteria: ObjectLiteral[] = [] - if (emailChecked !== null) { - filterCriteria.push({ emailChecked: emailChecked }) + if (withActivated !== null) { + filterCriteria.push({ withActivated: withActivated }) } - if (deletedAt !== null) { - filterCriteria.push({ deletedAt: deletedAt ? Not(IsNull()) : IsNull() }) + if (withDeleted !== null) { + filterCriteria.push({ withDeleted: withDeleted ? Not(IsNull()) : IsNull() }) } const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt'] From 0c0bfe1a1034816047c95d04ce2cb33adeaca76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Apr 2022 10:52:11 +0200 Subject: [PATCH 14/95] Rename to filterByActivated and filterByDeleted --- admin/src/graphql/searchUsers.js | 12 +++++----- admin/src/pages/Creation.spec.js | 16 ++++++------- admin/src/pages/Creation.vue | 4 ++-- admin/src/pages/UserSearch.spec.js | 24 +++++++++---------- admin/src/pages/UserSearch.vue | 5 ++-- backend/src/graphql/arg/SearchUsersArgs.ts | 4 ++-- backend/src/graphql/resolver/AdminResolver.ts | 12 +++++----- 7 files changed, 39 insertions(+), 38 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index 706927eb1..34c962678 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -5,15 +5,15 @@ export const searchUsers = gql` $searchText: String! $currentPage: Int $pageSize: Int - $withActivated: Boolean - $withDeleted: Boolean + $filterByActivated: Boolean + $filterByDeleted: Boolean ) { searchUsers( searchText: $searchText currentPage: $currentPage pageSize: $pageSize - withActivated: $withActivated - withDeleted: $withDeleted + filterByActivated: $filterByActivated + filterByDeleted: $filterByDeleted ) { userCount userList { @@ -24,8 +24,8 @@ export const searchUsers = gql` creation hasElopage emailConfirmationSend - withActivated - withDeleted + filterByActivated + filterByDeleted } } } diff --git a/admin/src/pages/Creation.spec.js b/admin/src/pages/Creation.spec.js index d1d6f0f2e..98c03d277 100644 --- a/admin/src/pages/Creation.spec.js +++ b/admin/src/pages/Creation.spec.js @@ -71,8 +71,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: true, - withDeleted: false, + filterByActivated: true, + filterByDeleted: false, }, }), ) @@ -271,8 +271,8 @@ describe('Creation', () => { searchText: 'XX', currentPage: 1, pageSize: 25, - withActivated: true, - withDeleted: false, + filterByActivated: true, + filterByDeleted: false, }, }), ) @@ -288,8 +288,8 @@ describe('Creation', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: true, - withDeleted: false, + filterByActivated: true, + filterByDeleted: false, }, }), ) @@ -305,8 +305,8 @@ describe('Creation', () => { searchText: '', currentPage: 2, pageSize: 25, - withActivated: true, - withDeleted: false, + filterByActivated: true, + filterByDeleted: false, }, }), ) diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue index 76d6077f5..54bc0d735 100644 --- a/admin/src/pages/Creation.vue +++ b/admin/src/pages/Creation.vue @@ -102,8 +102,8 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - withActivated: true, - withDeleted: false, + filterByActivated: true, + filterByDeleted: false, }, fetchPolicy: 'network-only', }) diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js index 602852608..2eb24f84b 100644 --- a/admin/src/pages/UserSearch.spec.js +++ b/admin/src/pages/UserSearch.spec.js @@ -82,8 +82,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: null, - withDeleted: null, + filterByActivated: null, + filterByDeleted: null, }, }), ) @@ -101,8 +101,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: true, - withDeleted: null, + filterByActivated: false, + filterByDeleted: null, }, }), ) @@ -121,8 +121,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: null, - withDeleted: true, + filterByActivated: null, + filterByDeleted: true, }, }), ) @@ -141,8 +141,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 2, pageSize: 25, - withActivated: null, - withDeleted: null, + filterByActivated: null, + filterByDeleted: null, }, }), ) @@ -161,8 +161,8 @@ describe('UserSearch', () => { searchText: 'search string', currentPage: 1, pageSize: 25, - withActivated: null, - withDeleted: null, + filterByActivated: null, + filterByDeleted: null, }, }), ) @@ -178,8 +178,8 @@ describe('UserSearch', () => { searchText: '', currentPage: 1, pageSize: 25, - withActivated: null, - withDeleted: null, + filterByActivated: null, + filterByDeleted: null, }, }), ) diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index f0bf60ae1..8a0a4b86f 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -3,6 +3,7 @@
+ {{ filterCheckedEmails ? $t('unregistered_emails') : $t('all_emails') }} @@ -85,8 +86,8 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - withActivated: this.filterCheckedEmails, - withDeleted: this.filterDeletedUser, + filterByActivated: this.filterCheckedEmails, // Wolle: check logic + filterByDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', }) diff --git a/backend/src/graphql/arg/SearchUsersArgs.ts b/backend/src/graphql/arg/SearchUsersArgs.ts index fab17e527..b47f39d56 100644 --- a/backend/src/graphql/arg/SearchUsersArgs.ts +++ b/backend/src/graphql/arg/SearchUsersArgs.ts @@ -12,8 +12,8 @@ export default class SearchUsersArgs { pageSize?: number @Field(() => Boolean, { nullable: true }) - withActivated?: boolean | null + filterByActivated?: boolean | null @Field(() => Boolean, { nullable: true }) - withDeleted?: boolean | null + filterByDeleted?: boolean | null } diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index bdb078ad1..7cc578a87 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -56,19 +56,19 @@ export class AdminResolver { searchText, currentPage = 1, pageSize = 25, - withActivated = null, - withDeleted = null, + filterByActivated = null, + filterByDeleted = null, }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) const filterCriteria: ObjectLiteral[] = [] - if (withActivated !== null) { - filterCriteria.push({ withActivated: withActivated }) + if (filterByActivated !== null) { + filterCriteria.push({ filterByActivated: filterByActivated }) } - if (withDeleted !== null) { - filterCriteria.push({ withDeleted: withDeleted ? Not(IsNull()) : IsNull() }) + if (filterByDeleted !== null) { + filterCriteria.push({ filterByDeleted: filterByDeleted ? Not(IsNull()) : IsNull() }) } const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt'] From 863ecfa4746c4f4f3a0bf5127119e0cce7251520 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 21 Apr 2022 10:58:22 +0200 Subject: [PATCH 15/95] migrate is_admin column in users as datetime with default null --- database/migrations/0034-drop_server_user_table.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/migrations/0034-drop_server_user_table.ts b/database/migrations/0034-drop_server_user_table.ts index 914c75457..fd5a9a682 100644 --- a/database/migrations/0034-drop_server_user_table.ts +++ b/database/migrations/0034-drop_server_user_table.ts @@ -5,10 +5,10 @@ add isAdmin COLUMN to users TABLE */ /* eslint-disable @typescript-eslint/no-explicit-any */ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn('ALTER TABLE `users` ADD COLUMN `is_admin` boolean DEFAULT false AFTER `language`;') + await queryFn('ALTER TABLE `users` ADD COLUMN `is_admin` datetime DEFAULT NULL AFTER `language`;') await queryFn( - 'UPDATE `users` SET `is_admin` = true WHERE `email` IN (SELECT `email` FROM `server_users`);', + 'UPDATE `users` AS `users`, (SELECT * FROM `server_users`) AS `server_users` SET users.`is_admin` = server_users.`modified` WHERE users.`email` IN (SELECT email from `server_users`);', ) await queryFn('DROP TABLE `server_users`;') @@ -30,7 +30,7 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`) await queryFn( - 'INSERT INTO `server_users` (`email`, `username`, `password`, `created`, `modified`) SELECT `email`, `first_name`, `password`, `created`, `created` FROM `users` WHERE `is_admin` = true;', + 'INSERT INTO `server_users` (`email`, `username`, `password`, `created`, `modified`) SELECT `email`, `first_name`, `password`, `is_admin`, `is_admin` FROM `users` WHERE `is_admin` IS NOT NULL;', ) await queryFn('ALTER TABLE `users` DROP COLUMN `is_admin`;') From ba648c67a98dd31c1bf07f494ae47529399a7364 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 21 Apr 2022 11:01:23 +0200 Subject: [PATCH 16/95] entity model users.isAdmin as nullable date --- database/entity/0034-drop_server_user_table/User.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/entity/0034-drop_server_user_table/User.ts b/database/entity/0034-drop_server_user_table/User.ts index 9192b92ff..1f56d13d2 100644 --- a/database/entity/0034-drop_server_user_table/User.ts +++ b/database/entity/0034-drop_server_user_table/User.ts @@ -58,8 +58,8 @@ export class User extends BaseEntity { @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) language: string - @Column({ name: 'is_admin', type: 'bool', nullable: false, default: false }) - isAdmin: boolean + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) referrerId?: number | null From 206737581fd1f58e423a3f90a2967e29f835acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Apr 2022 11:05:13 +0200 Subject: [PATCH 17/95] Fix logic of filterByActivated - Fix test with this. --- admin/src/pages/UserSearch.vue | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index 8a0a4b86f..44d3e4a03 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -3,8 +3,13 @@
- - {{ filterCheckedEmails ? $t('unregistered_emails') : $t('all_emails') }} + {{ + filterByActivated === null + ? $t('all_emails') + : filterByActivated === false + ? $t('unregistered_emails') + : '' + }} @@ -61,7 +66,7 @@ export default { searchResult: [], massCreation: [], criteria: '', - filterCheckedEmails: null, + filterByActivated: null, filterDeletedUser: null, rows: 0, currentPage: 1, @@ -71,7 +76,7 @@ export default { }, methods: { unconfirmedRegisterMails() { - this.filterCheckedEmails = this.filterCheckedEmails ? null : true + this.filterByActivated = this.filterByActivated === null ? false : null this.getUsers() }, deletedUserSearch() { @@ -86,7 +91,7 @@ export default { searchText: this.criteria, currentPage: this.currentPage, pageSize: this.perPage, - filterByActivated: this.filterCheckedEmails, // Wolle: check logic + filterByActivated: this.filterByActivated, filterByDeleted: this.filterDeletedUser, }, fetchPolicy: 'no-cache', From fa6fbe38c8e0ba1b44592146602cfb3938d9242d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 21 Apr 2022 11:05:51 +0200 Subject: [PATCH 18/95] User.isAdmin as nullable Date --- backend/src/graphql/model/User.ts | 4 ++-- backend/src/seeds/factory/user.ts | 2 +- backend/src/util/communityUser.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 1949592c0..4f577f60a 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -58,8 +58,8 @@ export class User { // `passphrase` text COLLATE utf8mb4_unicode_ci DEFAULT NULL, - @Field(() => Boolean) - isAdmin: boolean + @Field(() => Date, { nullable: true }) + isAdmin: Date | null // TODO this is a bit inconsistent with what we query from the database // therefore all those fields are now nullable with default value null diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 373a3da4f..4b5913d48 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -30,7 +30,7 @@ export const userFactory = async ( if (user.createdAt) dbUser.createdAt = user.createdAt if (user.deletedAt) dbUser.deletedAt = user.deletedAt - if (user.isAdmin) dbUser.isAdmin = user.isAdmin + if (user.isAdmin) dbUser.isAdmin = new Date() await dbUser.save() } } diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index 8b75b37a1..0d0d12f6c 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -17,7 +17,7 @@ const communityDbUser: dbUser = { createdAt: new Date(), emailChecked: false, language: '', - isAdmin: false, + isAdmin: null, publisherId: 0, passphrase: '', settings: [], From 0bf18a4f2b2c2f1cdaa3eb89e305a24a0e6e17d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Apr 2022 11:08:28 +0200 Subject: [PATCH 19/95] Revert unintenionally renamimngs --- admin/src/graphql/searchUsers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js index 34c962678..ddf759031 100644 --- a/admin/src/graphql/searchUsers.js +++ b/admin/src/graphql/searchUsers.js @@ -22,10 +22,10 @@ export const searchUsers = gql` lastName email creation + emailChecked hasElopage emailConfirmationSend - filterByActivated - filterByDeleted + deletedAt } } } From 50bddf49e4a1de785e5e413999c6c69186de2d84 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 21 Apr 2022 11:16:14 +0200 Subject: [PATCH 20/95] fix test for User.isAdmin as nullable date --- backend/src/graphql/resolver/UserResolver.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index b9e230afe..8e5cb299d 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -100,7 +100,7 @@ describe('UserResolver', () => { emailChecked: false, passphrase: expect.any(String), language: 'de', - isAdmin: false, + isAdmin: null, deletedAt: null, publisherId: 1234, referrerId: null, @@ -337,7 +337,7 @@ describe('UserResolver', () => { firstName: 'Bibi', hasElopage: false, id: expect.any(Number), - isAdmin: false, + isAdmin: null, klickTipp: { newsletterState: false, }, From e67a04b30f0bb6c63896ba08893c8164fcde4c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 21 Apr 2022 11:21:14 +0200 Subject: [PATCH 21/95] Renamed filterDeletedUser to filterByDeleted - Clarify logic. --- admin/src/pages/UserSearch.vue | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue index 44d3e4a03..f8ceac36c 100644 --- a/admin/src/pages/UserSearch.vue +++ b/admin/src/pages/UserSearch.vue @@ -13,7 +13,13 @@ - {{ filterDeletedUser ? $t('deleted_user') : $t('all_emails') }} + {{ + filterByDeleted === null + ? $t('all_emails') + : filterByDeleted === true + ? $t('deleted_user') + : '' + }}
@@ -67,7 +73,7 @@ export default { massCreation: [], criteria: '', filterByActivated: null, - filterDeletedUser: null, + filterByDeleted: null, rows: 0, currentPage: 1, perPage: 25, @@ -80,7 +86,7 @@ export default { this.getUsers() }, deletedUserSearch() { - this.filterDeletedUser = this.filterDeletedUser ? null : true + this.filterByDeleted = this.filterByDeleted === null ? true : null this.getUsers() }, getUsers() { @@ -92,7 +98,7 @@ export default { currentPage: this.currentPage, pageSize: this.perPage, filterByActivated: this.filterByActivated, - filterByDeleted: this.filterDeletedUser, + filterByDeleted: this.filterByDeleted, }, fetchPolicy: 'no-cache', }) From c3c3e556a0dd3b90a4c35bde3606f0aab37080fb Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 6 Apr 2022 14:46:45 +0200 Subject: [PATCH 22/95] convert admin_pending_creations to decimal --- .../AdminPendingCreation.ts | 33 +++++++++++++++++++ database/entity/AdminPendingCreation.ts | 2 +- .../0034-admin_pending_creations_decimal.ts | 33 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts create mode 100644 database/migrations/0034-admin_pending_creations_decimal.ts diff --git a/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts b/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts new file mode 100644 index 000000000..d204942b3 --- /dev/null +++ b/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts @@ -0,0 +1,33 @@ +import Decimal from 'decimal.js-light' +import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' + +@Entity('admin_pending_creations') +export class AdminPendingCreation extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ unsigned: true, nullable: false }) + userId: number + + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) + created: Date + + @Column({ type: 'datetime', nullable: false }) + date: Date + + @Column({ length: 256, nullable: true, default: null }) + memo: string + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + amount: Decimal + + @Column() + moderator: number +} diff --git a/database/entity/AdminPendingCreation.ts b/database/entity/AdminPendingCreation.ts index 03eeab883..a32590a22 100644 --- a/database/entity/AdminPendingCreation.ts +++ b/database/entity/AdminPendingCreation.ts @@ -1 +1 @@ -export { AdminPendingCreation } from './0015-admin_pending_creations/AdminPendingCreation' +export { AdminPendingCreation } from './0034-admin_pending_creations_decimal/AdminPendingCreation' diff --git a/database/migrations/0034-admin_pending_creations_decimal.ts b/database/migrations/0034-admin_pending_creations_decimal.ts new file mode 100644 index 000000000..6df1e563b --- /dev/null +++ b/database/migrations/0034-admin_pending_creations_decimal.ts @@ -0,0 +1,33 @@ +/* MIGRATION TO CHANGE `amount` FIELD TYPE TO `Decimal` ON `admin_pending_creations` */ + +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + // rename `amount` to `amount_bigint` + await queryFn('ALTER TABLE `admin_pending_creations` RENAME COLUMN `amount` TO `amount_bigint`;') + // add `amount` (decimal) + await queryFn( + 'ALTER TABLE `admin_pending_creations` ADD COLUMN `amount` DECIMAL(40,20) DEFAULT NULL AFTER `amount_bigint`;', + ) + // fill new `amount` column + await queryFn('UPDATE `admin_pending_creations` SET `amount` = `amount_bigint` DIV 10000;') + // make `amount` not nullable + await queryFn( + 'ALTER TABLE `admin_pending_creations` MODIFY COLUMN `amount` DECIMAL(40,20) NOT NULL;', + ) + // drop `amount_bitint` column + await queryFn('ALTER TABLE `admin_pending_creations` DROP COLUMN `amount_bigint`;') +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'ALTER TABLE `admin_pending_creations` ADD COLUMN `amount_bigint` bigint(20) DEFAULT NULL AFTER `amount`;', + ) + await queryFn('UPDATE `admin_pending_creations` SET `amount_bigint` = `amount` * 10000;') + await queryFn( + 'ALTER TABLE `admin_pending_creations` MODIFY COLUMN `amount_bigint` bigint(20) NOT NULL;', + ) + await queryFn('ALTER TABLE `admin_pending_creations` DROP COLUMN `amount`;') + await queryFn('ALTER TABLE `admin_pending_creations` RENAME COLUMN `amount_bigint` TO `amount`;') +} From 56ed35d6928a3a38c97b33c27c888fa346aafad7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 6 Apr 2022 14:48:28 +0200 Subject: [PATCH 23/95] backend fix types for admin_pending_creations is now decimal --- .../graphql/arg/CreatePendingCreationArgs.ts | 7 +++-- .../graphql/arg/UpdatePendingCreationArgs.ts | 7 +++-- backend/src/graphql/model/PendingCreation.ts | 9 +++--- .../graphql/model/UpdatePendingCreation.ts | 9 +++--- backend/src/graphql/model/UserAdmin.ts | 9 +++--- backend/src/graphql/resolver/AdminResolver.ts | 28 +++++++++---------- 6 files changed, 37 insertions(+), 32 deletions(-) diff --git a/backend/src/graphql/arg/CreatePendingCreationArgs.ts b/backend/src/graphql/arg/CreatePendingCreationArgs.ts index b90ad3231..0cadf5e62 100644 --- a/backend/src/graphql/arg/CreatePendingCreationArgs.ts +++ b/backend/src/graphql/arg/CreatePendingCreationArgs.ts @@ -1,4 +1,5 @@ -import { ArgsType, Field, Float, InputType, Int } from 'type-graphql' +import { ArgsType, Field, InputType, Int } from 'type-graphql' +import Decimal from 'decimal.js-light' @InputType() @ArgsType() @@ -6,8 +7,8 @@ export default class CreatePendingCreationArgs { @Field(() => String) email: string - @Field(() => Float) - amount: number + @Field(() => Decimal) + amount: Decimal @Field(() => String) memo: string diff --git a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts b/backend/src/graphql/arg/UpdatePendingCreationArgs.ts index 73f70c058..3cd85e84b 100644 --- a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts +++ b/backend/src/graphql/arg/UpdatePendingCreationArgs.ts @@ -1,4 +1,5 @@ -import { ArgsType, Field, Float, Int } from 'type-graphql' +import { ArgsType, Field, Int } from 'type-graphql' +import Decimal from 'decimal.js-light' @ArgsType() export default class UpdatePendingCreationArgs { @@ -8,8 +9,8 @@ export default class UpdatePendingCreationArgs { @Field(() => String) email: string - @Field(() => Float) - amount: number + @Field(() => Decimal) + amount: Decimal @Field(() => String) memo: string diff --git a/backend/src/graphql/model/PendingCreation.ts b/backend/src/graphql/model/PendingCreation.ts index 594657a59..500ba6f6b 100644 --- a/backend/src/graphql/model/PendingCreation.ts +++ b/backend/src/graphql/model/PendingCreation.ts @@ -1,4 +1,5 @@ import { ObjectType, Field, Int } from 'type-graphql' +import Decimal from 'decimal.js-light' @ObjectType() export class PendingCreation { @@ -23,12 +24,12 @@ export class PendingCreation { @Field(() => String) memo: string - @Field(() => Number) - amount: number + @Field(() => Decimal) + amount: Decimal @Field(() => Number) moderator: number - @Field(() => [Number]) - creation: number[] + @Field(() => [Decimal]) + creation: Decimal[] } diff --git a/backend/src/graphql/model/UpdatePendingCreation.ts b/backend/src/graphql/model/UpdatePendingCreation.ts index c8033f86e..85d3af2cc 100644 --- a/backend/src/graphql/model/UpdatePendingCreation.ts +++ b/backend/src/graphql/model/UpdatePendingCreation.ts @@ -1,4 +1,5 @@ import { ObjectType, Field } from 'type-graphql' +import Decimal from 'decimal.js-light' @ObjectType() export class UpdatePendingCreation { @@ -8,12 +9,12 @@ export class UpdatePendingCreation { @Field(() => String) memo: string - @Field(() => Number) - amount: number + @Field(() => Decimal) + amount: Decimal @Field(() => Number) moderator: number - @Field(() => [Number]) - creation: number[] + @Field(() => [Decimal]) + creation: Decimal[] } diff --git a/backend/src/graphql/model/UserAdmin.ts b/backend/src/graphql/model/UserAdmin.ts index 1d418c66c..8a1459c0f 100644 --- a/backend/src/graphql/model/UserAdmin.ts +++ b/backend/src/graphql/model/UserAdmin.ts @@ -1,9 +1,10 @@ -import { User } from '@entity/User' import { ObjectType, Field, Int } from 'type-graphql' +import Decimal from 'decimal.js-light' +import { User } from '@entity/User' @ObjectType() export class UserAdmin { - constructor(user: User, creation: number[], hasElopage: boolean, emailConfirmationSend: string) { + constructor(user: User, creation: Decimal[], hasElopage: boolean, emailConfirmationSend: string) { this.userId = user.id this.email = user.email this.firstName = user.firstName @@ -27,8 +28,8 @@ export class UserAdmin { @Field(() => String) lastName: string - @Field(() => [Number]) - creation: number[] + @Field(() => [Decimal]) + creation: Decimal[] @Field(() => Boolean) emailChecked: boolean diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 7ca3460ee..379412cdc 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -43,7 +43,7 @@ import CONFIG from '@/config' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? -const MAX_CREATION_AMOUNT = 1000 +const MAX_CREATION_AMOUNT = new Decimal(1000) const FULL_CREATION_AVAILABLE = [MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT] @Resolver() @@ -170,7 +170,7 @@ export class AdminResolver { @Mutation(() => [Number]) async createPendingCreation( @Args() { email, amount, memo, creationDate, moderator }: CreatePendingCreationArgs, - ): Promise { + ): Promise { const user = await dbUser.findOne({ email }, { withDeleted: true }) if (!user) { throw new Error(`Could not find user with email: ${email}`) @@ -186,7 +186,7 @@ export class AdminResolver { if (isCreationValid(creations, amount, creationDateObj)) { const adminPendingCreation = AdminPendingCreation.create() adminPendingCreation.userId = user.id - adminPendingCreation.amount = BigInt(amount) + adminPendingCreation.amount = amount adminPendingCreation.created = new Date() adminPendingCreation.date = creationDateObj adminPendingCreation.memo = memo @@ -251,14 +251,14 @@ export class AdminResolver { if (!isCreationValid(creations, amount, creationDateObj)) { throw new Error('Creation is not valid') } - pendingCreationToUpdate.amount = BigInt(amount) + pendingCreationToUpdate.amount = amount pendingCreationToUpdate.memo = memo pendingCreationToUpdate.date = new Date(creationDate) pendingCreationToUpdate.moderator = moderator await AdminPendingCreation.save(pendingCreationToUpdate) const result = new UpdatePendingCreation() - result.amount = parseInt(amount.toString()) + result.amount = amount result.memo = pendingCreationToUpdate.memo result.date = pendingCreationToUpdate.date result.moderator = pendingCreationToUpdate.moderator @@ -286,7 +286,7 @@ export class AdminResolver { return { ...pendingCreation, - amount: Number(pendingCreation.amount.toString()), + amount: pendingCreation.amount, firstName: user ? user.firstName : '', lastName: user ? user.lastName : '', email: user ? user.email : '', @@ -318,7 +318,7 @@ export class AdminResolver { if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a creation.') const creations = await getUserCreation(pendingCreation.userId, false) - if (!isCreationValid(creations, Number(pendingCreation.amount), pendingCreation.date)) { + if (!isCreationValid(creations, pendingCreation.amount, pendingCreation.date)) { throw new Error('Creation is not valid!!') } @@ -448,10 +448,10 @@ export class AdminResolver { interface CreationMap { id: number - creations: number[] + creations: Decimal[] } -async function getUserCreation(id: number, includePending = true): Promise { +async function getUserCreation(id: number, includePending = true): Promise { const creations = await getUserCreations([id], includePending) return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE } @@ -493,30 +493,30 @@ async function getUserCreations(ids: number[], includePending = true): Promise parseInt(raw.month) === month && parseInt(raw.id) === id, ) - return MAX_CREATION_AMOUNT - (creation ? Number(creation.sum) : 0) + return MAX_CREATION_AMOUNT.minus(creation ? creation.sum : 0) }), } }) } -function updateCreations(creations: number[], pendingCreation: AdminPendingCreation): number[] { +function updateCreations(creations: Decimal[], pendingCreation: AdminPendingCreation): Decimal[] { const index = getCreationIndex(pendingCreation.date.getMonth()) if (index < 0) { throw new Error('You cannot create GDD for a month older than the last three months.') } - creations[index] += parseInt(pendingCreation.amount.toString()) + creations[index] = creations[index].plus(pendingCreation.amount) return creations } -function isCreationValid(creations: number[], amount: number, creationDate: Date) { +function isCreationValid(creations: Decimal[], amount: Decimal, creationDate: Date) { const index = getCreationIndex(creationDate.getMonth()) if (index < 0) { throw new Error(`No Creation found!`) } - if (amount > creations[index]) { + if (amount.greaterThan(creations[index])) { throw new Error( `The amount (${amount} GDD) to be created exceeds the available amount (${creations[index]} GDD) for this month.`, ) From 7b86c4bc2470fa589977a25f2de2949e6cd9ed8e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 6 Apr 2022 14:53:03 +0200 Subject: [PATCH 24/95] admin use decimal instead of float for pending creations in graphql queries --- admin/src/graphql/createPendingCreation.js | 2 +- admin/src/graphql/updatePendingCreation.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/graphql/createPendingCreation.js b/admin/src/graphql/createPendingCreation.js index 183fa5b15..05402ed9f 100644 --- a/admin/src/graphql/createPendingCreation.js +++ b/admin/src/graphql/createPendingCreation.js @@ -3,7 +3,7 @@ import gql from 'graphql-tag' export const createPendingCreation = gql` mutation ( $email: String! - $amount: Float! + $amount: Decimal! $memo: String! $creationDate: String! $moderator: Int! diff --git a/admin/src/graphql/updatePendingCreation.js b/admin/src/graphql/updatePendingCreation.js index 77668f15b..cd0ae6c8e 100644 --- a/admin/src/graphql/updatePendingCreation.js +++ b/admin/src/graphql/updatePendingCreation.js @@ -4,7 +4,7 @@ export const updatePendingCreation = gql` mutation ( $id: Int! $email: String! - $amount: Float! + $amount: Decimal! $memo: String! $creationDate: String! $moderator: Int! From efcd75717a098abb670ee469073992192ac18dd6 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 20 Apr 2022 14:24:41 +0200 Subject: [PATCH 25/95] updated backend required database version --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 91f450369..1f134f23d 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0033-add_referrer_id', + DB_VERSION: '0034-admin_pending_creations_decimal.ts', DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0 CONFIG_VERSION: { DEFAULT: 'DEFAULT', From fdb64071d6cff9a65198594e20b554ed01dc8616 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 11:32:26 +0200 Subject: [PATCH 26/95] join tables to update is_admin --- database/migrations/0034-drop_server_user_table.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migrations/0034-drop_server_user_table.ts b/database/migrations/0034-drop_server_user_table.ts index fd5a9a682..be6b44489 100644 --- a/database/migrations/0034-drop_server_user_table.ts +++ b/database/migrations/0034-drop_server_user_table.ts @@ -8,7 +8,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis await queryFn('ALTER TABLE `users` ADD COLUMN `is_admin` datetime DEFAULT NULL AFTER `language`;') await queryFn( - 'UPDATE `users` AS `users`, (SELECT * FROM `server_users`) AS `server_users` SET users.`is_admin` = server_users.`modified` WHERE users.`email` IN (SELECT email from `server_users`);', + 'UPDATE users AS users INNER JOIN server_users AS server_users ON users.email = server_users.email SET users.is_admin = server_users.modified WHERE users.email IN (SELECT email from server_users);', ) await queryFn('DROP TABLE `server_users`;') From d346a1d09dec91ca5981a85dc8ccb79e25c883fe Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 11:52:10 +0200 Subject: [PATCH 27/95] test verify login --- .../src/graphql/resolver/UserResolver.test.ts | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 07b8e59e2..edd1ec7c5 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -5,7 +5,7 @@ import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/help import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createUser, setPassword } from '@/seeds/graphql/mutations' -import { login, logout } from '@/seeds/graphql/queries' +import { login, logout, verifyLogin } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' @@ -412,6 +412,75 @@ describe('UserResolver', () => { }) }) }) + + describe('verifyLogin', () => { + describe('unauthenticated', () => { + it('throws an error', async () => { + resetToken() + await expect(query({ query: verifyLogin })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('user exists but is not logged in', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + }) + + afterAll(async () => { + await cleanDB() + }) + + it('throws an error', async () => { + resetToken() + await expect(query({ query: verifyLogin })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + + describe('authenticated', () => { + const variables = { + email: 'bibi@bloxberg.de', + password: 'Aa12345_', + } + + beforeAll(async () => { + await query({ query: login, variables }) + }) + + afterAll(() => { + resetToken() + }) + + it('returns user object', async () => { + await expect(query({ query: verifyLogin })).resolves.toEqual( + expect.objectContaining({ + data: { + verifyLogin: { + email: 'bibi@bloxberg.de', + firstName: 'Bibi', + lastName: 'Bloxberg', + language: 'de', + coinanimation: true, + klickTipp: { + newsletterState: false, + }, + hasElopage: false, + publisherId: 1234, + isAdmin: false, + }, + }, + }), + ) + }) + }) + }) + }) }) describe('printTimeDuration', () => { From 276a1be889c51b6010a02562bad23ce09d697e8d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 12:49:23 +0200 Subject: [PATCH 28/95] test forgot password mutation --- .../src/graphql/resolver/UserResolver.test.ts | 65 ++++++++++++++++++- backend/src/seeds/graphql/mutations.ts | 6 ++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index edd1ec7c5..a2f5b2fdb 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,17 +1,18 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' +import { testEnvironment, headerPushMock, resetToken, cleanDB, resetEntity } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { createUser, setPassword } from '@/seeds/graphql/mutations' +import { createUser, setPassword, forgotPassword } from '@/seeds/graphql/mutations' import { login, logout, verifyLogin } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' import CONFIG from '@/config' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' -import { printTimeDuration } from './UserResolver' +import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail' +import { printTimeDuration, activationLink } from './UserResolver' // import { klicktippSignIn } from '@/apis/KlicktippController' @@ -22,6 +23,13 @@ jest.mock('@/mailer/sendAccountActivationEmail', () => { } }) +jest.mock('@/mailer/sendResetPasswordEmail', () => { + return { + __esModule: true, + sendResetPasswordEmail: jest.fn(), + } +}) + /* jest.mock('@/apis/KlicktippController', () => { return { @@ -481,6 +489,57 @@ describe('UserResolver', () => { }) }) }) + + describe('forgotPassword', () => { + const variables = { email: 'bibi@bloxberg.de' } + describe('user is not in DB', () => { + it('returns true', async () => { + await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + expect.objectContaining({ + data: { + forgotPassword: true, + }, + }), + ) + }) + }) + + describe('user exists in DB', () => { + let result: any + let loginEmailOptIn: LoginEmailOptIn[] + + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await resetEntity(LoginEmailOptIn) + result = await mutate({ mutation: forgotPassword, variables }) + loginEmailOptIn = await LoginEmailOptIn.find() + }) + + afterAll(async () => { + await cleanDB() + }) + + it('returns true', async () => { + await expect(result).toEqual( + expect.objectContaining({ + data: { + forgotPassword: true, + }, + }), + ) + }) + + it('sends reset password email', () => { + expect(sendResetPasswordEmail).toBeCalledWith({ + link: activationLink(loginEmailOptIn[0]), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + duration: expect.any(String), + }) + }) + }) + }) }) describe('printTimeDuration', () => { diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 298d56bdb..fc662cf19 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -18,6 +18,12 @@ export const setPassword = gql` } ` +export const forgotPassword = gql` + mutation ($email: String!) { + forgotPassword(email: $email) + } +` + export const updateUserInfos = gql` mutation ( $firstName: String From e30d1f723fcfa7ca078de4fe0225761f08724119 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 13:18:08 +0200 Subject: [PATCH 29/95] test queryOptIn --- .../src/graphql/resolver/UserResolver.test.ts | 59 ++++++++++++++++++- backend/src/seeds/graphql/queries.ts | 6 ++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index a2f5b2fdb..0b62e0c99 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -5,7 +5,7 @@ import { testEnvironment, headerPushMock, resetToken, cleanDB, resetEntity } fro import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createUser, setPassword, forgotPassword } from '@/seeds/graphql/mutations' -import { login, logout, verifyLogin } from '@/seeds/graphql/queries' +import { login, logout, verifyLogin, queryOptIn } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' @@ -538,6 +538,63 @@ describe('UserResolver', () => { duration: expect.any(String), }) }) + + describe('request reset password again', () => { + it('thows an error', async () => { + await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('email already sent less than 10 minutes minutes ago')], + }), + ) + }) + }) + }) + }) + + describe('queryOptIn', () => { + let loginEmailOptIn: LoginEmailOptIn[] + + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + loginEmailOptIn = await LoginEmailOptIn.find() + }) + + afterAll(async () => { + await cleanDB() + }) + + describe('wrong optin code', () => { + it('throws an error', async () => { + await expect( + query({ query: queryOptIn, variables: { optIn: 'not-valid' } }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + // keep Whitspace in error message! + new GraphQLError(`Could not find any entity of type "LoginEmailOptIn" matching: { + "verificationCode": "not-valid" +}`), + ], + }), + ) + }) + }) + + describe('correct optin code', () => { + it('returns true', async () => { + await expect( + query({ + query: queryOptIn, + variables: { optIn: loginEmailOptIn[0].verificationCode.toString() }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + queryOptIn: true, + }, + }), + ) + }) }) }) }) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 11a675eeb..76a386953 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -43,6 +43,12 @@ export const logout = gql` } ` +export const queryOptIn = gql` + query ($optIn: String!) { + queryOptIn(optIn: $optIn) + } +` + export const transactionsQuery = gql` query ( $currentPage: Int = 1 From 73fe46c39d80b5f867eb015d2072b9bc44357c25 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 25 Apr 2022 14:03:38 +0200 Subject: [PATCH 30/95] also change memo column --- .../AdminPendingCreation.ts | 2 +- .../0034-admin_pending_creations_decimal.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts b/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts index d204942b3..3cd83a3a5 100644 --- a/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts +++ b/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts @@ -16,7 +16,7 @@ export class AdminPendingCreation extends BaseEntity { @Column({ type: 'datetime', nullable: false }) date: Date - @Column({ length: 256, nullable: true, default: null }) + @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) memo: string @Column({ diff --git a/database/migrations/0034-admin_pending_creations_decimal.ts b/database/migrations/0034-admin_pending_creations_decimal.ts index 6df1e563b..d3648f376 100644 --- a/database/migrations/0034-admin_pending_creations_decimal.ts +++ b/database/migrations/0034-admin_pending_creations_decimal.ts @@ -1,4 +1,7 @@ -/* MIGRATION TO CHANGE `amount` FIELD TYPE TO `Decimal` ON `admin_pending_creations` */ +/* MIGRATION TO CHANGE SEVERAL FIELDS ON `admin_pending_creations` + * - `amount` FIELD TYPE TO `Decimal` + * - `memo` FIELD TYPE TO `varchar(255)`, collate `utf8mb4_unicode_ci` + */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -18,9 +21,15 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) // drop `amount_bitint` column await queryFn('ALTER TABLE `admin_pending_creations` DROP COLUMN `amount_bigint`;') + + // change `memo` to varchar(255), collate utf8mb4_unicode_ci + await queryFn( + 'ALTER TABLE `admin_pending_creations` MODIFY COLUMN `memo` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL;', + ) } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE `admin_pending_creations` MODIFY COLUMN `memo` text DEFAULT NULL;') await queryFn( 'ALTER TABLE `admin_pending_creations` ADD COLUMN `amount_bigint` bigint(20) DEFAULT NULL AFTER `amount`;', ) From 0264931e5824d4d8c087502d035bdb7b6057242c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 14:07:31 +0200 Subject: [PATCH 31/95] test update user infos mutation. Remove publisher ID from update user infos as it is never used --- .../src/graphql/resolver/UserResolver.test.ts | 177 +++++++++++++++++- backend/src/graphql/resolver/UserResolver.ts | 15 +- 2 files changed, 176 insertions(+), 16 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 0b62e0c99..06924699a 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -4,7 +4,7 @@ import { testEnvironment, headerPushMock, resetToken, cleanDB, resetEntity } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { createUser, setPassword, forgotPassword } from '@/seeds/graphql/mutations' +import { createUser, setPassword, forgotPassword, updateUserInfos } from '@/seeds/graphql/mutations' import { login, logout, verifyLogin, queryOptIn } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' @@ -93,7 +93,7 @@ describe('UserResolver', () => { }) describe('filling all tables', () => { - it('saves the user in login_user table', () => { + it('saves the user in users table', () => { expect(user).toEqual([ { id: expect.any(Number), @@ -597,6 +597,179 @@ describe('UserResolver', () => { }) }) }) + + describe('updateUserInfos', () => { + describe('unauthenticated', () => { + it('throws an error', async () => { + resetToken() + await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { + email: 'bibi@bloxberg.de', + password: 'Aa12345_', + }, + }) + }) + + afterAll(async () => { + await cleanDB() + }) + + it('returns true', async () => { + await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + expect.objectContaining({ + data: { + updateUserInfos: true, + }, + }), + ) + }) + + describe('first-name, last-name and language', () => { + it('updates the fields in DB', async () => { + await mutate({ + mutation: updateUserInfos, + variables: { + firstName: 'Benjamin', + lastName: 'Blümchen', + locale: 'en', + }, + }) + await expect(User.findOne()).resolves.toEqual( + expect.objectContaining({ + firstName: 'Benjamin', + lastName: 'Blümchen', + language: 'en', + }), + ) + }) + }) + + describe('language is not valid', () => { + it('thows an error', async () => { + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + locale: 'not-valid', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError(`"not-valid" isn't a valid language`)], + }), + ) + }) + }) + + describe('password', () => { + describe('wrong old password', () => { + it('throws an error', async () => { + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + password: 'wrong password', + passwordNew: 'Aa12345_', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Old password is invalid')], + }), + ) + }) + }) + + describe('invalid new password', () => { + it('throws an error', async () => { + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + password: 'Aa12345_', + passwordNew: 'Aa12345', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', + ), + ], + }), + ) + }) + }) + + describe('correct old and new password', () => { + it('returns true', async () => { + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + password: 'Aa12345_', + passwordNew: 'Bb12345_', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { updateUserInfos: true }, + }), + ) + }) + + it('can login wtih new password', async () => { + await expect( + query({ + query: login, + variables: { + email: 'bibi@bloxberg.de', + password: 'Bb12345_', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + login: expect.objectContaining({ + email: 'bibi@bloxberg.de', + }), + }, + }), + ) + }) + + it('cannot login wtih old password', async () => { + await expect( + query({ + query: login, + variables: { + email: 'bibi@bloxberg.de', + password: 'Aa12345_', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('No user with this credentials')], + }), + ) + }) + }) + }) + }) + }) }) describe('printTimeDuration', () => { diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 137c09622..a4d4f9115 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -529,15 +529,7 @@ export class UserResolver { @Mutation(() => Boolean) async updateUserInfos( @Args() - { - firstName, - lastName, - language, - publisherId, - password, - passwordNew, - coinanimation, - }: UpdateUserInfosArgs, + { firstName, lastName, language, password, passwordNew, coinanimation }: UpdateUserInfosArgs, @Ctx() context: Context, ): Promise { const userEntity = getUser(context) @@ -581,11 +573,6 @@ export class UserResolver { userEntity.privKey = encryptedPrivkey } - // Save publisherId only if Elopage is not yet registered - if (publisherId && !(await this.hasElopage(context))) { - userEntity.publisherId = publisherId - } - const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('READ UNCOMMITTED') From 5cd2c045aa6f625a214a4f91fd9378f0740cc6bb Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 14:08:24 +0200 Subject: [PATCH 32/95] test coverage backend to 58% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee602a343..3d046fcda 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -528,7 +528,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 55 + min_coverage: 58 token: ${{ github.token }} ########################################################################## From e2957e0b345a1136ce1404a725ea7dc186a32682 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 25 Apr 2022 14:17:45 +0200 Subject: [PATCH 33/95] config value for the redeem URL was missing --- deployment/bare_metal/.env.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 316fb60c2..a1751a859 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -21,6 +21,7 @@ WEBHOOK_GITHUB_BRANCH=master COMMUNITY_NAME="Gradido Development Stage1" COMMUNITY_URL=https://stage1.gradido.net/ COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register +COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" # backend From a4a92812bf3e21f9b0b6feb05cca3e84c1d0662d Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 25 Apr 2022 15:14:55 +0200 Subject: [PATCH 34/95] adjusted migrtion number to 35 --- .../AdminPendingCreation.ts | 0 database/entity/AdminPendingCreation.ts | 2 +- ...tions_decimal.ts => 0035-admin_pending_creations_decimal.ts} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename database/entity/{0034-admin_pending_creations_decimal => 0035-admin_pending_creations_decimal}/AdminPendingCreation.ts (100%) rename database/migrations/{0034-admin_pending_creations_decimal.ts => 0035-admin_pending_creations_decimal.ts} (100%) diff --git a/database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts b/database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts similarity index 100% rename from database/entity/0034-admin_pending_creations_decimal/AdminPendingCreation.ts rename to database/entity/0035-admin_pending_creations_decimal/AdminPendingCreation.ts diff --git a/database/entity/AdminPendingCreation.ts b/database/entity/AdminPendingCreation.ts index a32590a22..b2b37d7c4 100644 --- a/database/entity/AdminPendingCreation.ts +++ b/database/entity/AdminPendingCreation.ts @@ -1 +1 @@ -export { AdminPendingCreation } from './0034-admin_pending_creations_decimal/AdminPendingCreation' +export { AdminPendingCreation } from './0035-admin_pending_creations_decimal/AdminPendingCreation' diff --git a/database/migrations/0034-admin_pending_creations_decimal.ts b/database/migrations/0035-admin_pending_creations_decimal.ts similarity index 100% rename from database/migrations/0034-admin_pending_creations_decimal.ts rename to database/migrations/0035-admin_pending_creations_decimal.ts From a4ae002693c2a6eced4f9e066ef9d60585ab7c36 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 16:01:26 +0200 Subject: [PATCH 35/95] round balance down before subtracting hold available amount --- backend/src/util/virtualTransactions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/util/virtualTransactions.ts b/backend/src/util/virtualTransactions.ts index 8c1aec65b..08d44b48d 100644 --- a/backend/src/util/virtualTransactions.ts +++ b/backend/src/util/virtualTransactions.ts @@ -70,6 +70,7 @@ const virtualDecayTransaction = ( typeId: TransactionTypeId.DECAY, amount: decay.decay ? decay.roundedDecay : new Decimal(0), balance: decay.balance + .toDecimalPlaces(2, Decimal.ROUND_DOWN) .minus(holdAvailabeAmount.toString()) .toDecimalPlaces(2, Decimal.ROUND_DOWN), balanceDate: time, From 22fcf28291f3641a1203128a4d1de353cb6458de Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 16:06:18 +0200 Subject: [PATCH 36/95] remove strange comments --- backend/src/graphql/resolver/UserResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index a4d4f9115..4fe2589ec 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -251,8 +251,6 @@ export class UserResolver { user.hasElopage = await this.hasElopage({ ...context, user: dbUser }) if (!user.hasElopage && publisherId) { user.publisherId = publisherId - // TODO: Check if we can use updateUserInfos - // await this.updateUserInfos({ publisherId }, { pubKey: loginUser.pubKey }) dbUser.publisherId = publisherId DbUser.save(dbUser) } From 54e119f88d1ad704393596058fc0029d61bb868d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 25 Apr 2022 16:20:00 +0200 Subject: [PATCH 37/95] fix test after alter is admin field --- backend/src/graphql/resolver/UserResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 424c2051c..c658476a4 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -481,7 +481,7 @@ describe('UserResolver', () => { }, hasElopage: false, publisherId: 1234, - isAdmin: false, + isAdmin: null, }, }, }), From 6aad14024755ddbfedc1e3ee85ac9bff2faa9751 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 25 Apr 2022 16:36:33 +0200 Subject: [PATCH 38/95] fix database version requirement for backend --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 63968c235..1eee1b9a4 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0035-admin_pending_creations_decimal.ts', + DB_VERSION: '0035-admin_pending_creations_decimal', DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0 CONFIG_VERSION: { DEFAULT: 'DEFAULT', From 84d4d41f2233211c6d454da74ee95f5b00b2f3f1 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 25 Apr 2022 16:51:48 +0200 Subject: [PATCH 39/95] v1.8.0 --- CHANGELOG.md | 46 +++++++++++++++++++++++++++++++++++++++++++ admin/package.json | 2 +- backend/package.json | 2 +- database/package.json | 2 +- frontend/package.json | 2 +- package.json | 2 +- 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53376946c..5d8b71dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,54 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.8.0](https://github.com/gradido/gradido/compare/1.7.1...1.8.0) + +- Fix: database version requirement for backend corrected [`#1835`](https://github.com/gradido/gradido/pull/1835) +- feat: More User Resolver Tests [`#1827`](https://github.com/gradido/gradido/pull/1827) +- fix: Round Decay with Tranasction Links [`#1834`](https://github.com/gradido/gradido/pull/1834) +- Fix: config value for the redeem URL was missing [`#1828`](https://github.com/gradido/gradido/pull/1828) +- Refactor: Database admin pending creations use decimal [`#1748`](https://github.com/gradido/gradido/pull/1748) +- refactor: Drop Server User Table [`#1808`](https://github.com/gradido/gradido/pull/1808) +- 1816 expired link are not highlighted [`#1821`](https://github.com/gradido/gradido/pull/1821) +- 1812 put qr code into popup on generate [`#1820`](https://github.com/gradido/gradido/pull/1820) +- Docu: Federation image [`#1817`](https://github.com/gradido/gradido/pull/1817) +- 1813 qr code popup [`#1819`](https://github.com/gradido/gradido/pull/1819) +- Fix: cross-env for windows [`#1822`](https://github.com/gradido/gradido/pull/1822) +- fix: Double Load Transaction Links [`#1818`](https://github.com/gradido/gradido/pull/1818) +- Generated link in backend should also give back the base url [`#1745`](https://github.com/gradido/gradido/pull/1745) +- 1731 style startDecayStartblock, style Adapted across pages [`#1809`](https://github.com/gradido/gradido/pull/1809) +- Refactor: Frontend bake in community info [`#1750`](https://github.com/gradido/gradido/pull/1750) +- fix: Load Transaction Link Details on Click [`#1806`](https://github.com/gradido/gradido/pull/1806) +- devops: Deploy Seed in Backend [`#1790`](https://github.com/gradido/gradido/pull/1790) +- refactor: Balance Model and Decay Rounding [`#1780`](https://github.com/gradido/gradido/pull/1780) +- change config DECAY_START_TIME in UTC 0000 [`#1807`](https://github.com/gradido/gradido/pull/1807) +- 1751 make gdt visible only if explicitly clicked [`#1752`](https://github.com/gradido/gradido/pull/1752) +- add Tab system from bootstrap in SearchUserTable Userdata [`#1744`](https://github.com/gradido/gradido/pull/1744) +- Fix: Certbot renewal [`#1789`](https://github.com/gradido/gradido/pull/1789) +- 🍰 Add Wallet Link To Mails [`#1765`](https://github.com/gradido/gradido/pull/1765) +- 1633 display qr code on link in transaction list [`#1661`](https://github.com/gradido/gradido/pull/1661) +- 1755 insert additional text when redeeming [`#1756`](https://github.com/gradido/gradido/pull/1756) +- refactor: Define Context Interface [`#1762`](https://github.com/gradido/gradido/pull/1762) +- fix: Elopage Status [`#1742`](https://github.com/gradido/gradido/pull/1742) +- Refactor: Frontend decay start block as static config value [`#1749`](https://github.com/gradido/gradido/pull/1749) +- better date format for reddem valid date [`#1758`](https://github.com/gradido/gradido/pull/1758) +- add insert shadow in summary links transaction type [`#1754`](https://github.com/gradido/gradido/pull/1754) +- Feature: JWT duration is now 30min by default [`#1747`](https://github.com/gradido/gradido/pull/1747) +- Docu: Scope of Gradido [`#1746`](https://github.com/gradido/gradido/pull/1746) +- fix: Check That Recipient User Has Activated Account to Receive Coins [`#1743`](https://github.com/gradido/gradido/pull/1743) +- Fix: Fixed config dist version to properly reflect new password reset url [`#1737`](https://github.com/gradido/gradido/pull/1737) +- 503 transaction list pagination pages clickable [`#1677`](https://github.com/gradido/gradido/pull/1677) +- if no recipientEmail else form.email [`#1722`](https://github.com/gradido/gradido/pull/1722) +- 1727 change button text and observe spelling [`#1728`](https://github.com/gradido/gradido/pull/1728) +- 1729 load spinner if pending balance [`#1730`](https://github.com/gradido/gradido/pull/1730) +- transaction type remains when jumping from the verification back [`#1724`](https://github.com/gradido/gradido/pull/1724) +- text for toast expand link copied [`#1726`](https://github.com/gradido/gradido/pull/1726) + #### [1.7.1](https://github.com/gradido/gradido/compare/1.7.0...1.7.1) +> 1 April 2022 + +- v1.7.1 [`#1721`](https://github.com/gradido/gradido/pull/1721) - fix: Localize Dates on Redeem Transaction Link Page [`#1720`](https://github.com/gradido/gradido/pull/1720) - fix: Round Virtual Transaction Link Transaction [`#1718`](https://github.com/gradido/gradido/pull/1718) - larger icon and deacy information if center [`#1719`](https://github.com/gradido/gradido/pull/1719) diff --git a/admin/package.json b/admin/package.json index 3d3919954..c5b2e60f5 100644 --- a/admin/package.json +++ b/admin/package.json @@ -3,7 +3,7 @@ "description": "Administraion Interface for Gradido", "main": "index.js", "author": "Moriz Wahl", - "version": "1.7.1", + "version": "1.8.0", "license": "MIT", "private": false, "scripts": { diff --git a/backend/package.json b/backend/package.json index 8654f4cc7..c5318d674 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "gradido-backend", - "version": "1.7.1", + "version": "1.8.0", "description": "Gradido unified backend providing an API-Service for Gradido Transactions", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/backend", diff --git a/database/package.json b/database/package.json index a1fffa882..13c638c79 100644 --- a/database/package.json +++ b/database/package.json @@ -1,6 +1,6 @@ { "name": "gradido-database", - "version": "1.7.1", + "version": "1.8.0", "description": "Gradido Database Tool to execute database migrations", "main": "src/index.ts", "repository": "https://github.com/gradido/gradido/database", diff --git a/frontend/package.json b/frontend/package.json index b3091d4b4..18021e705 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-vue-gradido-wallet", - "version": "1.7.1", + "version": "1.8.0", "private": true, "scripts": { "start": "node run/server.js", diff --git a/package.json b/package.json index 2ff37c71a..c8abef594 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gradido", - "version": "1.7.1", + "version": "1.8.0", "description": "Gradido", "main": "index.js", "repository": "git@github.com:gradido/gradido.git", From 6d48b6f4e39f97ddf05e4fe5241156db8c43d5f4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 26 Apr 2022 09:27:55 +0200 Subject: [PATCH 40/95] fix: Confirm Creation with Decimal --- backend/src/graphql/resolver/AdminResolver.ts | 5 ++--- backend/src/seeds/graphql/mutations.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 379412cdc..2009af3b0 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -333,8 +333,7 @@ export class AdminResolver { decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, receivedCallDate) newBalance = decay.balance } - // TODO pending creations decimal - newBalance = newBalance.add(new Decimal(Number(pendingCreation.amount)).toString()) + newBalance = newBalance.add(pendingCreation.amount.toString()) const transaction = new DbTransaction() transaction.typeId = TransactionTypeId.CREATION @@ -516,7 +515,7 @@ function isCreationValid(creations: Decimal[], amount: Decimal, creationDate: Da throw new Error(`No Creation found!`) } - if (amount.greaterThan(creations[index])) { + if (amount.greaterThan(creations[index].toString())) { throw new Error( `The amount (${amount} GDD) to be created exceeds the available amount (${creations[index]} GDD) for this month.`, ) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index fc662cf19..601b1fbbf 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -86,7 +86,7 @@ export const createTransactionLink = gql` export const createPendingCreation = gql` mutation ( $email: String! - $amount: Float! + $amount: Decimal! $memo: String! $creationDate: String! $moderator: Int! From 3c9a12d29311182140cb399e447b70bfd93e5c35 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 26 Apr 2022 11:05:30 +0200 Subject: [PATCH 41/95] open modal only for id --- frontend/src/components/ClipboardCopy.vue | 12 +++++++++++- .../TransactionLinks/TransactionLink.vue | 14 ++++++++++++++ frontend/src/locales/de.json | 2 +- frontend/src/locales/en.json | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue index 936f6db1a..e8fb6e084 100644 --- a/frontend/src/components/ClipboardCopy.vue +++ b/frontend/src/components/ClipboardCopy.vue @@ -1,6 +1,6 @@