mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge pull request #1293 from gradido/paginate-user-table
feat: Paginate User Table
This commit is contained in:
commit
cee930b8f7
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -520,7 +520,7 @@ jobs:
|
|||||||
report_name: Coverage Backend
|
report_name: Coverage Backend
|
||||||
type: lcov
|
type: lcov
|
||||||
result_path: ./backend/coverage/lcov.info
|
result_path: ./backend/coverage/lcov.info
|
||||||
min_coverage: 41
|
min_coverage: 45
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|||||||
@ -1,14 +1,22 @@
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
export const searchUsers = gql`
|
export const searchUsers = gql`
|
||||||
query ($searchText: String!) {
|
query ($searchText: String!, $currentPage: Int, $pageSize: Int, $notActivated: Boolean) {
|
||||||
searchUsers(searchText: $searchText) {
|
searchUsers(
|
||||||
userId
|
searchText: $searchText
|
||||||
firstName
|
currentPage: $currentPage
|
||||||
lastName
|
pageSize: $pageSize
|
||||||
email
|
notActivated: $notActivated
|
||||||
creation
|
) {
|
||||||
emailChecked
|
userCount
|
||||||
|
userList {
|
||||||
|
userId
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
email
|
||||||
|
creation
|
||||||
|
emailChecked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"all_emails": "Alle Nutzer",
|
||||||
"bookmark": "bookmark",
|
"bookmark": "bookmark",
|
||||||
"confirmed": "bestätigt",
|
"confirmed": "bestätigt",
|
||||||
"creation_form": {
|
"creation_form": {
|
||||||
@ -53,7 +54,7 @@
|
|||||||
"transactionlist": {
|
"transactionlist": {
|
||||||
"title": "Alle geschöpften Transaktionen für den Nutzer"
|
"title": "Alle geschöpften Transaktionen für den Nutzer"
|
||||||
},
|
},
|
||||||
"unregistered_emails": "Unregistrierte E-Mails",
|
"unregistered_emails": "Nur unregistrierte Nutzer",
|
||||||
"unregister_mail": {
|
"unregister_mail": {
|
||||||
"button": "Registrierungs-Email bestätigen, jetzt senden",
|
"button": "Registrierungs-Email bestätigen, jetzt senden",
|
||||||
"error": "Fehler beim Senden des Bestätigungs-Links an den Benutzer: {message}",
|
"error": "Fehler beim Senden des Bestätigungs-Links an den Benutzer: {message}",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"all_emails": "All users",
|
||||||
"bookmark": "Remember",
|
"bookmark": "Remember",
|
||||||
"confirmed": "confirmed",
|
"confirmed": "confirmed",
|
||||||
"creation_form": {
|
"creation_form": {
|
||||||
@ -53,7 +54,7 @@
|
|||||||
"transactionlist": {
|
"transactionlist": {
|
||||||
"title": "All creation-transactions for the user"
|
"title": "All creation-transactions for the user"
|
||||||
},
|
},
|
||||||
"unregistered_emails": "Unregistered e-mails",
|
"unregistered_emails": "Only unregistered users",
|
||||||
"unregister_mail": {
|
"unregister_mail": {
|
||||||
"button": "Confirm registration email, send now",
|
"button": "Confirm registration email, send now",
|
||||||
"error": "Error sending the confirmation link to the user: {message}",
|
"error": "Error sending the confirmation link to the user: {message}",
|
||||||
|
|||||||
@ -6,22 +6,25 @@ const localVue = global.localVue
|
|||||||
|
|
||||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
searchUsers: [
|
searchUsers: {
|
||||||
{
|
userCount: 2,
|
||||||
userId: 1,
|
userList: [
|
||||||
firstName: 'Bibi',
|
{
|
||||||
lastName: 'Bloxberg',
|
userId: 1,
|
||||||
email: 'bibi@bloxberg.de',
|
firstName: 'Bibi',
|
||||||
creation: [200, 400, 600],
|
lastName: 'Bloxberg',
|
||||||
},
|
email: 'bibi@bloxberg.de',
|
||||||
{
|
creation: [200, 400, 600],
|
||||||
userId: 2,
|
},
|
||||||
firstName: 'Benjamin',
|
{
|
||||||
lastName: 'Blümchen',
|
userId: 2,
|
||||||
email: 'benjamin@bluemchen.de',
|
firstName: 'Benjamin',
|
||||||
creation: [800, 600, 400],
|
lastName: 'Blümchen',
|
||||||
},
|
email: 'benjamin@bluemchen.de',
|
||||||
],
|
creation: [800, 600, 400],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -227,6 +230,22 @@ describe('Creation', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('watchers', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls API when criteria changes', async () => {
|
||||||
|
await wrapper.setData({ criteria: 'XX' })
|
||||||
|
expect(apolloQueryMock).toBeCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls API when currentPage changes', async () => {
|
||||||
|
await wrapper.setData({ currentPage: 2 })
|
||||||
|
expect(apolloQueryMock).toBeCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('apollo returns error', () => {
|
describe('apollo returns error', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apolloQueryMock.mockRejectedValue({
|
apolloQueryMock.mockRejectedValue({
|
||||||
|
|||||||
@ -18,6 +18,13 @@
|
|||||||
:creation="creation"
|
:creation="creation"
|
||||||
@update-item="updateItem"
|
@update-item="updateItem"
|
||||||
/>
|
/>
|
||||||
|
<b-pagination
|
||||||
|
pills
|
||||||
|
v-model="currentPage"
|
||||||
|
per-page="perPage"
|
||||||
|
:total-rows="rows"
|
||||||
|
align="center"
|
||||||
|
></b-pagination>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col cols="12" lg="6" class="shadow p-3 mb-5 rounded bg-info">
|
<b-col cols="12" lg="6" class="shadow p-3 mb-5 rounded bg-info">
|
||||||
<user-table
|
<user-table
|
||||||
@ -101,6 +108,9 @@ export default {
|
|||||||
radioSelectedMass: '',
|
radioSelectedMass: '',
|
||||||
criteria: '',
|
criteria: '',
|
||||||
creation: [null, null, null],
|
creation: [null, null, null],
|
||||||
|
rows: 0,
|
||||||
|
currentPage: 1,
|
||||||
|
perPage: 25,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
@ -113,10 +123,13 @@ export default {
|
|||||||
query: searchUsers,
|
query: searchUsers,
|
||||||
variables: {
|
variables: {
|
||||||
searchText: this.criteria,
|
searchText: this.criteria,
|
||||||
|
currentPage: this.currentPage,
|
||||||
|
pageSize: this.perPage,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.itemsList = result.data.searchUsers.map((user) => {
|
this.rows = result.data.searchUsers.userCount
|
||||||
|
this.itemsList = result.data.searchUsers.userList.map((user) => {
|
||||||
return {
|
return {
|
||||||
...user,
|
...user,
|
||||||
showDetails: false,
|
showDetails: false,
|
||||||
@ -153,5 +166,13 @@ export default {
|
|||||||
this.itemsMassCreation = []
|
this.itemsMassCreation = []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
currentPage() {
|
||||||
|
this.getUsers()
|
||||||
|
},
|
||||||
|
criteria() {
|
||||||
|
this.getUsers()
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -5,15 +5,18 @@ const localVue = global.localVue
|
|||||||
|
|
||||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
searchUsers: [
|
searchUsers: {
|
||||||
{
|
userCount: 1,
|
||||||
firstName: 'Bibi',
|
userList: [
|
||||||
lastName: 'Bloxberg',
|
{
|
||||||
email: 'bibi@bloxberg.de',
|
firstName: 'Bibi',
|
||||||
creation: [200, 400, 600],
|
lastName: 'Bloxberg',
|
||||||
emailChecked: false,
|
email: 'bibi@bloxberg.de',
|
||||||
},
|
creation: [200, 400, 600],
|
||||||
],
|
emailChecked: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<b-button block variant="danger" @click="unconfirmedRegisterMails">
|
<b-button block variant="danger" @click="unconfirmedRegisterMails">
|
||||||
<b-icon icon="envelope" variant="light"></b-icon>
|
<b-icon icon="envelope" variant="light"></b-icon>
|
||||||
{{ $t('unregistered_emails') }}
|
{{ filterCheckedEmails ? $t('all_emails') : $t('unregistered_emails') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
<label>{{ $t('user_search') }}</label>
|
<label>{{ $t('user_search') }}</label>
|
||||||
@ -21,6 +21,14 @@
|
|||||||
:fieldsTable="fields"
|
:fieldsTable="fields"
|
||||||
:criteria="criteria"
|
:criteria="criteria"
|
||||||
/>
|
/>
|
||||||
|
<b-pagination
|
||||||
|
pills
|
||||||
|
size="lg"
|
||||||
|
v-model="currentPage"
|
||||||
|
per-page="perPage"
|
||||||
|
:total-rows="rows"
|
||||||
|
align="center"
|
||||||
|
></b-pagination>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -67,14 +75,16 @@ export default {
|
|||||||
beforeLastMonth: {
|
beforeLastMonth: {
|
||||||
short: this.$moment().subtract(2, 'month').format('MMMM'),
|
short: this.$moment().subtract(2, 'month').format('MMMM'),
|
||||||
},
|
},
|
||||||
|
filterCheckedEmails: false,
|
||||||
|
rows: 0,
|
||||||
|
currentPage: 1,
|
||||||
|
perPage: 25,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
unconfirmedRegisterMails() {
|
unconfirmedRegisterMails() {
|
||||||
this.searchResult = this.searchResult.filter((user) => {
|
this.filterCheckedEmails = !this.filterCheckedEmails
|
||||||
return !user.emailChecked
|
this.getUsers()
|
||||||
})
|
|
||||||
},
|
},
|
||||||
getUsers() {
|
getUsers() {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
@ -82,16 +92,25 @@ export default {
|
|||||||
query: searchUsers,
|
query: searchUsers,
|
||||||
variables: {
|
variables: {
|
||||||
searchText: this.criteria,
|
searchText: this.criteria,
|
||||||
|
currentPage: this.currentPage,
|
||||||
|
pageSize: this.perPage,
|
||||||
|
notActivated: this.filterCheckedEmails,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.searchResult = result.data.searchUsers
|
this.rows = result.data.searchUsers.userCount
|
||||||
|
this.searchResult = result.data.searchUsers.userList
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$toasted.error(error.message)
|
this.$toasted.error(error.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
currentPage() {
|
||||||
|
this.getUsers()
|
||||||
|
},
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getUsers()
|
this.getUsers()
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||||
module.exports = {
|
module.exports = async () => {
|
||||||
verbose: true,
|
process.env.TZ = 'UTC'
|
||||||
preset: 'ts-jest',
|
return {
|
||||||
collectCoverage: true,
|
verbose: true,
|
||||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'],
|
preset: 'ts-jest',
|
||||||
moduleNameMapper: {
|
collectCoverage: true,
|
||||||
'@entity/(.*)': '<rootDir>/../database/build/entity/$1',
|
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'],
|
||||||
// This is hack to fix a problem with the library `ts-mysql-migrate` which does differentiate between its ts/js state
|
moduleNameMapper: {
|
||||||
'@dbTools/(.*)':
|
'@entity/(.*)': '<rootDir>/../database/build/entity/$1',
|
||||||
process.env.NODE_ENV === 'development'
|
// This is hack to fix a problem with the library `ts-mysql-migrate` which does differentiate between its ts/js state
|
||||||
? '<rootDir>/../database/src/$1'
|
'@dbTools/(.*)':
|
||||||
: '<rootDir>/../database/build/src/$1',
|
process.env.NODE_ENV === 'development'
|
||||||
},
|
? '<rootDir>/../database/src/$1'
|
||||||
|
: '<rootDir>/../database/build/src/$1',
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import CONFIG from '../config'
|
|||||||
|
|
||||||
const klicktippConnector = new KlicktippConnector()
|
const klicktippConnector = new KlicktippConnector()
|
||||||
|
|
||||||
export const signIn = async (
|
export const klicktippSignIn = async (
|
||||||
email: string,
|
email: string,
|
||||||
language: string,
|
language: string,
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
|
|||||||
16
backend/src/graphql/arg/SearchUsersArgs.ts
Normal file
16
backend/src/graphql/arg/SearchUsersArgs.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ArgsType, Field, Int } from 'type-graphql'
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export default class SearchUsersArgs {
|
||||||
|
@Field(() => String)
|
||||||
|
searchText: string
|
||||||
|
|
||||||
|
@Field(() => Int, { nullable: true })
|
||||||
|
currentPage?: number
|
||||||
|
|
||||||
|
@Field(() => Int, { nullable: true })
|
||||||
|
pageSize?: number
|
||||||
|
|
||||||
|
@Field(() => Boolean, { nullable: true })
|
||||||
|
notActivated?: boolean
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { ObjectType, Field } from 'type-graphql'
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class UserAdmin {
|
export class UserAdmin {
|
||||||
@ -20,3 +20,12 @@ export class UserAdmin {
|
|||||||
@Field(() => Boolean)
|
@Field(() => Boolean)
|
||||||
emailChecked: boolean
|
emailChecked: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class SearchUsersResult {
|
||||||
|
@Field(() => Int)
|
||||||
|
userCount: number
|
||||||
|
|
||||||
|
@Field(() => [UserAdmin])
|
||||||
|
userList: UserAdmin[]
|
||||||
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx } from 'type-graphql'
|
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx } from 'type-graphql'
|
||||||
import { getCustomRepository, Raw } from 'typeorm'
|
import { getCustomRepository, Raw } from 'typeorm'
|
||||||
import { UserAdmin } from '../model/UserAdmin'
|
import { UserAdmin, SearchUsersResult } from '../model/UserAdmin'
|
||||||
import { PendingCreation } from '../model/PendingCreation'
|
import { PendingCreation } from '../model/PendingCreation'
|
||||||
import { CreatePendingCreations } from '../model/CreatePendingCreations'
|
import { CreatePendingCreations } from '../model/CreatePendingCreations'
|
||||||
import { UpdatePendingCreation } from '../model/UpdatePendingCreation'
|
import { UpdatePendingCreation } from '../model/UpdatePendingCreation'
|
||||||
@ -14,6 +14,7 @@ import { LoginPendingTasksAdminRepository } from '../../typeorm/repository/Login
|
|||||||
import { UserRepository } from '../../typeorm/repository/User'
|
import { UserRepository } from '../../typeorm/repository/User'
|
||||||
import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs'
|
import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs'
|
||||||
import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs'
|
import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs'
|
||||||
|
import SearchUsersArgs from '../arg/SearchUsersArgs'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { Transaction } from '@entity/Transaction'
|
import { Transaction } from '@entity/Transaction'
|
||||||
import { TransactionCreation } from '@entity/TransactionCreation'
|
import { TransactionCreation } from '@entity/TransactionCreation'
|
||||||
@ -26,11 +27,13 @@ import { LoginUserRepository } from '../../typeorm/repository/LoginUser'
|
|||||||
@Resolver()
|
@Resolver()
|
||||||
export class AdminResolver {
|
export class AdminResolver {
|
||||||
@Authorized([RIGHTS.SEARCH_USERS])
|
@Authorized([RIGHTS.SEARCH_USERS])
|
||||||
@Query(() => [UserAdmin])
|
@Query(() => SearchUsersResult)
|
||||||
async searchUsers(@Arg('searchText') searchText: string): Promise<UserAdmin[]> {
|
async searchUsers(
|
||||||
|
@Args() { searchText, currentPage = 1, pageSize = 25, notActivated = false }: SearchUsersArgs,
|
||||||
|
): Promise<SearchUsersResult> {
|
||||||
const userRepository = getCustomRepository(UserRepository)
|
const userRepository = getCustomRepository(UserRepository)
|
||||||
const users = await userRepository.findBySearchCriteria(searchText)
|
const users = await userRepository.findBySearchCriteria(searchText)
|
||||||
const adminUsers = await Promise.all(
|
let adminUsers = await Promise.all(
|
||||||
users.map(async (user) => {
|
users.map(async (user) => {
|
||||||
const adminUser = new UserAdmin()
|
const adminUser = new UserAdmin()
|
||||||
adminUser.userId = user.id
|
adminUser.userId = user.id
|
||||||
@ -42,7 +45,12 @@ export class AdminResolver {
|
|||||||
return adminUser
|
return adminUser
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
return adminUsers
|
if (notActivated) adminUsers = adminUsers.filter((u) => !u.emailChecked)
|
||||||
|
const first = (currentPage - 1) * pageSize
|
||||||
|
return {
|
||||||
|
userCount: adminUsers.length,
|
||||||
|
userList: adminUsers.slice(first, first + pageSize),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
getKlickTippUser,
|
getKlickTippUser,
|
||||||
getKlicktippTagMap,
|
getKlicktippTagMap,
|
||||||
unsubscribe,
|
unsubscribe,
|
||||||
signIn,
|
klicktippSignIn,
|
||||||
} from '../../apis/KlicktippController'
|
} from '../../apis/KlicktippController'
|
||||||
import { RIGHTS } from '../../auth/RIGHTS'
|
import { RIGHTS } from '../../auth/RIGHTS'
|
||||||
import SubscribeNewsletterArgs from '../arg/SubscribeNewsletterArgs'
|
import SubscribeNewsletterArgs from '../arg/SubscribeNewsletterArgs'
|
||||||
@ -36,6 +36,6 @@ export class KlicktippResolver {
|
|||||||
async subscribeNewsletter(
|
async subscribeNewsletter(
|
||||||
@Args() { email, language }: SubscribeNewsletterArgs,
|
@Args() { email, language }: SubscribeNewsletterArgs,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return await signIn(email, language)
|
return await klicktippSignIn(email, language)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
|||||||
import { User } from '@entity/User'
|
import { User } from '@entity/User'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import { sendAccountActivationEmail } from '../../mailer/sendAccountActivationEmail'
|
import { sendAccountActivationEmail } from '../../mailer/sendAccountActivationEmail'
|
||||||
|
import { klicktippSignIn } from '../../apis/KlicktippController'
|
||||||
|
|
||||||
jest.mock('../../mailer/sendAccountActivationEmail', () => {
|
jest.mock('../../mailer/sendAccountActivationEmail', () => {
|
||||||
return {
|
return {
|
||||||
@ -21,6 +22,13 @@ jest.mock('../../mailer/sendAccountActivationEmail', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
jest.mock('../../apis/KlicktippController', () => {
|
||||||
|
return {
|
||||||
|
__esModule: true,
|
||||||
|
klicktippSignIn: jest.fn(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let mutate: any
|
let mutate: any
|
||||||
let con: any
|
let con: any
|
||||||
|
|
||||||
@ -220,6 +228,157 @@ describe('UserResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('setPassword', () => {
|
||||||
|
const createUserMutation = gql`
|
||||||
|
mutation (
|
||||||
|
$email: String!
|
||||||
|
$firstName: String!
|
||||||
|
$lastName: String!
|
||||||
|
$language: String!
|
||||||
|
$publisherId: Int
|
||||||
|
) {
|
||||||
|
createUser(
|
||||||
|
email: $email
|
||||||
|
firstName: $firstName
|
||||||
|
lastName: $lastName
|
||||||
|
language: $language
|
||||||
|
publisherId: $publisherId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const createUserVariables = {
|
||||||
|
email: 'peter@lustig.de',
|
||||||
|
firstName: 'Peter',
|
||||||
|
lastName: 'Lustig',
|
||||||
|
language: 'de',
|
||||||
|
publisherId: 1234,
|
||||||
|
}
|
||||||
|
|
||||||
|
const setPasswordMutation = gql`
|
||||||
|
mutation ($code: String!, $password: String!) {
|
||||||
|
setPassword(code: $code, password: $password)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
let result: any
|
||||||
|
let emailOptIn: string
|
||||||
|
|
||||||
|
describe('valid optin code and valid password', () => {
|
||||||
|
let loginUser: any
|
||||||
|
let newLoginUser: any
|
||||||
|
let newUser: any
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||||
|
const loginEmailOptIn = await getRepository(LoginEmailOptIn)
|
||||||
|
.createQueryBuilder('login_email_optin')
|
||||||
|
.getMany()
|
||||||
|
loginUser = await getRepository(LoginUser).createQueryBuilder('login_user').getMany()
|
||||||
|
emailOptIn = loginEmailOptIn[0].verificationCode.toString()
|
||||||
|
result = await mutate({
|
||||||
|
mutation: setPasswordMutation,
|
||||||
|
variables: { code: emailOptIn, password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
newLoginUser = await getRepository(LoginUser).createQueryBuilder('login_user').getMany()
|
||||||
|
newUser = await getRepository(User).createQueryBuilder('state_user').getMany()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await resetDB()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets email checked to true', () => {
|
||||||
|
expect(newLoginUser[0].emailChecked).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates the password', () => {
|
||||||
|
expect(newLoginUser[0].password).toEqual('3917921995996627700')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates the public Key on both user tables', () => {
|
||||||
|
expect(newLoginUser[0].pubKey).toEqual(expect.any(Buffer))
|
||||||
|
expect(newLoginUser[0].pubKey).not.toEqual(loginUser[0].pubKey)
|
||||||
|
expect(newLoginUser[0].pubKey).toEqual(newUser[0].pubkey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates the private Key', () => {
|
||||||
|
expect(newLoginUser[0].privKey).toEqual(expect.any(Buffer))
|
||||||
|
expect(newLoginUser[0].privKey).not.toEqual(loginUser[0].privKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes the optin', async () => {
|
||||||
|
await expect(
|
||||||
|
getRepository(LoginEmailOptIn).createQueryBuilder('login_email_optin').getMany(),
|
||||||
|
).resolves.toHaveLength(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the klicktipp API', () => {
|
||||||
|
expect(klicktippSignIn).toBeCalledWith(
|
||||||
|
loginUser[0].email,
|
||||||
|
loginUser[0].language,
|
||||||
|
loginUser[0].firstName,
|
||||||
|
loginUser[0].lastName,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns true', () => {
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('no valid password', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||||
|
const loginEmailOptIn = await getRepository(LoginEmailOptIn)
|
||||||
|
.createQueryBuilder('login_email_optin')
|
||||||
|
.getMany()
|
||||||
|
emailOptIn = loginEmailOptIn[0].verificationCode.toString()
|
||||||
|
result = await mutate({
|
||||||
|
mutation: setPasswordMutation,
|
||||||
|
variables: { code: emailOptIn, password: 'not-valid' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await resetDB()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error', () => {
|
||||||
|
expect(result).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('no valid optin code', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||||
|
result = await mutate({
|
||||||
|
mutation: setPasswordMutation,
|
||||||
|
variables: { code: 'not valid', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await resetDB()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws an error', () => {
|
||||||
|
expect(result).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('Could not login with emailVerificationCode')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
|||||||
import { sendResetPasswordEmail } from '../../mailer/sendResetPasswordEmail'
|
import { sendResetPasswordEmail } from '../../mailer/sendResetPasswordEmail'
|
||||||
import { sendAccountActivationEmail } from '../../mailer/sendAccountActivationEmail'
|
import { sendAccountActivationEmail } from '../../mailer/sendAccountActivationEmail'
|
||||||
import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys'
|
import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys'
|
||||||
import { signIn } from '../../apis/KlicktippController'
|
import { klicktippSignIn } from '../../apis/KlicktippController'
|
||||||
import { RIGHTS } from '../../auth/RIGHTS'
|
import { RIGHTS } from '../../auth/RIGHTS'
|
||||||
import { ServerUserRepository } from '../../typeorm/repository/ServerUser'
|
import { ServerUserRepository } from '../../typeorm/repository/ServerUser'
|
||||||
import { ROLE_ADMIN } from '../../auth/ROLES'
|
import { ROLE_ADMIN } from '../../auth/ROLES'
|
||||||
@ -641,7 +641,12 @@ export class UserResolver {
|
|||||||
// TODO do we always signUp the user? How to handle things with old users?
|
// TODO do we always signUp the user? How to handle things with old users?
|
||||||
if (optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER) {
|
if (optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER) {
|
||||||
try {
|
try {
|
||||||
await signIn(loginUser.email, loginUser.language, loginUser.firstName, loginUser.lastName)
|
await klicktippSignIn(
|
||||||
|
loginUser.email,
|
||||||
|
loginUser.language,
|
||||||
|
loginUser.firstName,
|
||||||
|
loginUser.lastName,
|
||||||
|
)
|
||||||
} catch {
|
} catch {
|
||||||
// TODO is this a problem?
|
// TODO is this a problem?
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MiddlewareFn } from 'type-graphql'
|
import { MiddlewareFn } from 'type-graphql'
|
||||||
import { /* signIn, */ getKlickTippUser } from '../apis/KlicktippController'
|
import { /* klicktippSignIn, */ getKlickTippUser } from '../apis/KlicktippController'
|
||||||
import { KlickTipp } from '../graphql/model/KlickTipp'
|
import { KlickTipp } from '../graphql/model/KlickTipp'
|
||||||
import CONFIG from '../config/index'
|
import CONFIG from '../config/index'
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ import CONFIG from '../config/index'
|
|||||||
// // Do Something here before resolver is called
|
// // Do Something here before resolver is called
|
||||||
// const result = await next()
|
// const result = await next()
|
||||||
// // Do Something here after resolver is completed
|
// // Do Something here after resolver is completed
|
||||||
// await signIn(result.email, result.language, result.firstName, result.lastName)
|
// await klicktippSignIn(result.email, result.language, result.firstName, result.lastName)
|
||||||
// return result
|
// return result
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { CreateBibiBloxbergSeed } from './seeds/users/bibi-bloxberg.seed'
|
|||||||
import { CreateRaeuberHotzenplotzSeed } from './seeds/users/raeuber-hotzenplotz.seed'
|
import { CreateRaeuberHotzenplotzSeed } from './seeds/users/raeuber-hotzenplotz.seed'
|
||||||
import { CreateBobBaumeisterSeed } from './seeds/users/bob-baumeister.seed'
|
import { CreateBobBaumeisterSeed } from './seeds/users/bob-baumeister.seed'
|
||||||
import { CreateGarrickOllivanderSeed } from './seeds/users/garrick-ollivander.seed'
|
import { CreateGarrickOllivanderSeed } from './seeds/users/garrick-ollivander.seed'
|
||||||
|
import { CreateUserSeed } from './seeds/create-user.seed'
|
||||||
import { DecayStartBlockSeed } from './seeds/decay-start-block.seed'
|
import { DecayStartBlockSeed } from './seeds/decay-start-block.seed'
|
||||||
import { resetDB, pool, migration } from './helpers'
|
import { resetDB, pool, migration } from './helpers'
|
||||||
|
|
||||||
@ -45,6 +46,10 @@ const run = async (command: string) => {
|
|||||||
await runSeeder(CreateBibiBloxbergSeed)
|
await runSeeder(CreateBibiBloxbergSeed)
|
||||||
await runSeeder(CreateRaeuberHotzenplotzSeed)
|
await runSeeder(CreateRaeuberHotzenplotzSeed)
|
||||||
await runSeeder(CreateBobBaumeisterSeed)
|
await runSeeder(CreateBobBaumeisterSeed)
|
||||||
|
// eslint-disable-next-line prefer-spread
|
||||||
|
Array.apply(null, Array(96)).forEach(async () => {
|
||||||
|
await runSeeder(CreateUserSeed)
|
||||||
|
})
|
||||||
await runSeeder(CreateGarrickOllivanderSeed)
|
await runSeeder(CreateGarrickOllivanderSeed)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import { Factory, Seeder } from 'typeorm-seeding'
|
import { Factory, Seeder } from 'typeorm-seeding'
|
||||||
import { User } from '../../entity/User'
|
import { userSeeder } from './helpers/user-helpers'
|
||||||
// import { LoginUser } from '../../entity/LoginUser'
|
|
||||||
|
|
||||||
export class CreateUserSeed implements Seeder {
|
export class CreateUserSeed implements Seeder {
|
||||||
public async run(factory: Factory): Promise<void> {
|
public async run(factory: Factory): Promise<void> {
|
||||||
// const loginUser = await factory(LoginUser)().make()
|
await userSeeder(factory, {})
|
||||||
// console.log(loginUser.email)
|
|
||||||
await factory(User)().create()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import { Factory } from 'typeorm-seeding'
|
|||||||
|
|
||||||
export const userSeeder = async (factory: Factory, userData: UserInterface): Promise<void> => {
|
export const userSeeder = async (factory: Factory, userData: UserInterface): Promise<void> => {
|
||||||
const user = await factory(User)(createUserContext(userData)).create()
|
const user = await factory(User)(createUserContext(userData)).create()
|
||||||
|
if (!userData.email) userData.email = user.email
|
||||||
const loginUser = await factory(LoginUser)(createLoginUserContext(userData)).create()
|
const loginUser = await factory(LoginUser)(createLoginUserContext(userData)).create()
|
||||||
await factory(LoginUserBackup)(createLoginUserBackupContext(userData, loginUser)).create()
|
await factory(LoginUserBackup)(createLoginUserBackupContext(userData, loginUser)).create()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user