Browse Source

FEATURE | search in users table

merge-requests/74/head
D-Klimishen 3 years ago
parent
commit
b1b764f718
  1. 8
      src/core/namespaces/sessions.namespace.ts
  2. 21
      src/core/namespaces/users.namespace.ts
  3. 13
      src/domain/sessions/services/sessions.service.ts
  4. 4
      src/domain/users/entities/user-factories-relation.entity.ts
  5. 13
      src/domain/users/entities/user.entity.ts
  6. 78
      src/domain/users/services/users-list.service.ts
  7. 6
      src/rest/admin/users/controllers/admin-users.controller.ts
  8. 38
      src/rest/admin/users/dtos/get-users-list.dto.ts
  9. 33
      src/rest/admin/users/services/admin-users.service.ts

8
src/core/namespaces/sessions.namespace.ts

@ -65,6 +65,14 @@ export namespace Sessions { @@ -65,6 +65,14 @@ export namespace Sessions {
*/
refresh(token: string): Promise<ITokenPair>
/**
* Метод для отримання останньої сесії користувача за типом
* @param {userId} userId - userId
* @param {SessionType} type - тип сесії
* @returns Повертає access i reshresh токени
*/
getLastUserSessionByType(userId: number, type: Sessions.SessionType): Promise<ISession>
//** Завешення сессії */
/**
* Метод для завешення сессії користувача

21
src/core/namespaces/users.namespace.ts

@ -50,11 +50,11 @@ export namespace Users { @@ -50,11 +50,11 @@ export namespace Users {
passwordSalt: string
/** */
factories?: Users.IUserFactoryRelation[]
factoriesRelations?: Users.IUserFactoryRelation[]
loginOnDesktop?: Date
loginOnDesktopDate?: string
loginOnMobile?: Date
loginOnMobileDate?: string
}
/**
@ -200,12 +200,15 @@ export namespace Users { @@ -200,12 +200,15 @@ export namespace Users {
excludeIds?: number[]
includeIds?: number[]
soonBirthday?: boolean
searchFields?: {
firstName: string
lastName: string
middleName: string
factories: string
}
firstName?: string
lastName?: string
middleName?: string
email?: string
login?: string
status?: Status
loginOnDesktopDate?: string
loginOnMobileDate?: string
factories?: string
}
export interface IUsersService {

13
src/domain/sessions/services/sessions.service.ts

@ -49,6 +49,19 @@ export class SessionsService implements Sessions.ISessionsService { @@ -49,6 +49,19 @@ export class SessionsService implements Sessions.ISessionsService {
return tokens
}
public async getLastUserSessionByType(userId: number, type: Sessions.SessionType) {
const session = await this.sessionsRepository.findOne(
{ userId, type },
{
order: {
type: 'DESC',
},
},
)
if (session) return session
return null
}
private generateTokens(userId: number, role: Users.Role) {
return {
accessToken: this.jwtService.createToken({ id: userId, role }),

4
src/domain/users/entities/user-factories-relation.entity.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { Users } from 'src/core'
import { Factory } from 'src/domain/factories/entities'
import { User } from 'src/domain/users/entities'
import { User, UserInfo } from 'src/domain/users/entities'
import {
Column,
CreateDateColumn,
@ -27,7 +27,7 @@ export class UserFactoriesRelations implements Users.IUserFactoryRelation { @@ -27,7 +27,7 @@ export class UserFactoriesRelations implements Users.IUserFactoryRelation {
@ManyToOne(
() => User,
user => user.factories,
user => user.factoriesRelation,
{ onDelete: 'CASCADE' },
)
@JoinColumn({ name: 'userId' })

13
src/domain/users/entities/user.entity.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import { Users } from 'src/core'
import { Session } from 'src/domain/sessions/entities'
import {
Column,
Entity,
@ -29,7 +30,7 @@ export class User implements Users.UserModel { @@ -29,7 +30,7 @@ export class User implements Users.UserModel {
@Column({ type: 'char', default: Users.Status.Active, nullable: false })
status: Users.Status
@Column({ nullable: true, select: false, unique: true })
@Column({ nullable: true, unique: true })
login?: string
@Column({ type: 'varchar', nullable: false, unique: true })
@ -48,6 +49,12 @@ export class User implements Users.UserModel { @@ -48,6 +49,12 @@ export class User implements Users.UserModel {
() => UserFactoriesRelations,
userFactoriesRelations => userFactoriesRelations.factory,
)
@JoinColumn({ name: 'factories' })
factories?: Users.IUserFactoryRelation[]
@JoinColumn({ name: 'factoriesRelation' })
factoriesRelation?: Users.IUserFactoryRelation[]
@Column({ nullable: true })
loginOnDesktopDate?: string
@Column({ nullable: true })
loginOnMobileDate?: string
}

78
src/domain/users/services/users-list.service.ts

@ -11,7 +11,7 @@ import { @@ -11,7 +11,7 @@ import {
USERS_REPOSITORY,
} from '../consts'
import { IUsersRepository } from '../interfaces'
import _ from 'lodash'
import * as _ from 'lodash'
@Injectable()
export class UsersListService {
@ -21,9 +21,9 @@ export class UsersListService { @@ -21,9 +21,9 @@ export class UsersListService {
const query = this.usersRepository
.createQueryBuilder('it')
.leftJoinAndSelect('it.info', 'info')
.leftJoinAndSelect('it.factories', 'factories')
this.addSearchStringToQuery(query, pagination.searchString, params.searchFields)
console.log(query.getQueryAndParameters())
this.addSearchStringToQuery(query, pagination.searchString, params)
await this.addSearchParams(query, params)
const { items, count } = await paginateAndGetMany(query, pagination, 'it')
@ -35,28 +35,66 @@ export class UsersListService { @@ -35,28 +35,66 @@ export class UsersListService {
private addSearchStringToQuery(
query: SelectQueryBuilder<Users.UserModel>,
searchString: string,
params: Users.IGetUsersListParams['searchFields'],
params: Users.IGetUsersListParams,
) {
if (!searchString || _.isEmpty(params)) return null
if (searchString) {
const toSearch = `%${searchString}%`
const toSearch = `%${!searchString ? '' : searchString}%`
query.andWhere(
new Brackets(subQuery => {
subQuery.where('info.firstName ILIKE :search', { search: toSearch })
subQuery.orWhere('info.lastName ILIKE :search', { search: toSearch })
subQuery.orWhere('info.middleName ILIKE :search', { search: toSearch })
subQuery.orWhere('it.email ILIKE :search', { search: toSearch })
subQuery.orWhere('it.login ILIKE :search', { search: toSearch })
subQuery.orWhere('it.status ILIKE :search', { search: toSearch })
subQuery.orWhere('it.loginOnDesktopDate ILIKE :search', { search: toSearch })
subQuery.orWhere('it.loginOnMobileDate ILIKE :search', { search: toSearch })
subQuery.orWhere('info.position ILIKE :search', { search: toSearch })
subQuery.orWhere('it.phoneNumber ILIKE :search', { search: toSearch })
}),
)
}
if (_.isEmpty(params)) return null
console.log('params', params)
query.andWhere(
new Brackets(subQuery => {
subQuery.where(
new Brackets(qb => {
qb.where('info.firstName ILIKE :search', { search: toSearch })
if (params.firstName)
qb.andWhere('info.firstName ILIKE :firstName', {
firstName: params.firstName,
})
}),
)
subQuery.orWhere('info.lastName ILIKE :search', { search: toSearch })
subQuery.orWhere('info.middleName ILIKE :search', { search: toSearch })
subQuery.orWhere('info.position ILIKE :search', { search: toSearch })
subQuery.orWhere('it.phoneNumber ILIKE :search', { search: toSearch })
subQuery.orWhere('it.email ILIKE :search', { search: toSearch })
if (params.firstName) {
console.log(`%${params.firstName}%`)
subQuery.andWhere('info.firstName ILIKE :firstName', {
firstName: `%${params.firstName}%`,
})
}
if (params.lastName) {
subQuery.andWhere('info.lastName ILIKE :lastName', {
lastName: params.lastName,
})
}
if (params.middleName) {
subQuery.andWhere('info.middleName ILIKE :middleName', {
middleName: params.middleName,
})
}
if (params.email) {
subQuery.andWhere('it.email ILIKE :email', { email: params.email })
}
if (params.login) {
subQuery.andWhere('it.login ILIKE :login', { login: params.login })
}
if (params.status) {
subQuery.andWhere('it.status ILIKE :status', { status: params.status })
}
if (params.loginOnDesktopDate) {
subQuery.andWhere('it.loginOnDesktopDate ILIKE :loginOnDesktopDate', {
loginOnDesktopDate: params.loginOnDesktopDate,
})
}
if (params.loginOnMobileDate) {
subQuery.andWhere('it.loginOnMobileDate ILIKE :loginOnMobileDate', {
loginOnMobileDate: params.loginOnMobileDate,
})
}
}),
)

6
src/rest/admin/users/controllers/admin-users.controller.ts

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
import { Body, Controller, Patch, Post, Get, Query } from '@nestjs/common'
import { Body, Controller, Patch, Post, Get, Query, ValidationPipe } from '@nestjs/common'
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'
import { Users } from 'src/core'
import { IPagination } from 'src/core/interfaces'
import { RoleGuard } from 'src/domain/sessions/decorators'
import { ReqPagination } from 'src/shared'
import { GetUsersListDto, StoreUserPayloadDto, UpdateUserStatusDto } from '../dtos'
import { GetUsersListDto, StoreUserPayloadDto, UpdateUserStatusDto, UsersDto } from '../dtos'
import { AdminUsersService } from '../services'
@ApiTags('Admin | Users')
@ -20,7 +20,7 @@ export class AdminUsersController { @@ -20,7 +20,7 @@ export class AdminUsersController {
})
// @RoleGuard(Users.Role.Admin)
@Get()
public async getUsersList(@ReqPagination() pagination: IPagination, @Query() params: any) {
public async getUsersList(@ReqPagination() pagination: IPagination, @Query() params: UsersDto) {
return await this.adminUsersService.getUsersList(pagination, params)
}

38
src/rest/admin/users/dtos/get-users-list.dto.ts

@ -26,3 +26,41 @@ export class GetUsersListDto extends UsersListDto { @@ -26,3 +26,41 @@ export class GetUsersListDto extends UsersListDto {
@DtoProperty()
count: number
}
export class UsersDto {
@DtoPropertyOptional({ isArray: true, type: Number })
excludeIds?: number[]
@DtoPropertyOptional({ isArray: true, type: Number })
includeIds?: number[]
@DtoPropertyOptional({ type: Boolean })
soonBirthday?: boolean
@DtoPropertyOptional({ type: String })
firstName?: string
@DtoPropertyOptional({ type: String })
lastName?: string
@DtoPropertyOptional({ type: String })
middleName?: string
@DtoPropertyOptional({ type: String })
email?: string
@DtoPropertyOptional({ type: String })
login?: string
@DtoPropertyOptional()
status?: any
@DtoPropertyOptional({ type: String })
loginOnDesktopDate?: string
@DtoPropertyOptional({ type: String })
loginOnMobileDate?: string
@DtoPropertyOptional({ type: String })
factories?: string
}

33
src/rest/admin/users/services/admin-users.service.ts

@ -1,15 +1,40 @@ @@ -1,15 +1,40 @@
import { Inject, Injectable } from '@nestjs/common'
import { Users } from 'src/core'
import { USERS_SERVICE } from 'src/core/consts'
import { Sessions, Users } from 'src/core'
import { SESSIONS_SERVICE, USERS_SERVICE } from 'src/core/consts'
import { StoreUserPayloadDto, UpdateUserStatusDto } from '../dtos'
import { IPagination } from 'src/core/interfaces'
import * as _ from 'lodash'
@Injectable()
export class AdminUsersService {
constructor(@Inject(USERS_SERVICE) private readonly usersDomainService: Users.IUsersService) {}
constructor(
@Inject(USERS_SERVICE) private readonly usersDomainService: Users.IUsersService,
@Inject(SESSIONS_SERVICE) private readonly sessionsService: Sessions.ISessionsService,
) {}
public async getUsersList(pagination: IPagination, params: any) {
return this.usersDomainService.getList(pagination, params)
const usersList = await this.usersDomainService.getList(
pagination,
_.omitBy(params, _.isNil),
)
await Promise.all(
usersList.items.map(async user => {
user.loginOnMobileDate = await (
await this.sessionsService.getLastUserSessionByType(
user.id,
Sessions.SessionType.App,
)
)?.updatedAt
user.loginOnDesktopDate = await (
await this.sessionsService.getLastUserSessionByType(
user.id,
Sessions.SessionType.Desktop,
)
)?.updatedAt
}),
)
return usersList
}
public async create(dto: StoreUserPayloadDto) {

Loading…
Cancel
Save