Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(j-s): User National Id #17976

Merged
merged 7 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ export class AuthService {
return undefined
}

return await res.json()
const users = await res.json()

// TODO: Support login with multiple users
return users[0]
}

async findDefender(nationalId: string): Promise<User | undefined> {
Expand All @@ -62,7 +65,9 @@ export class AuthService {
} catch (error) {
if (error instanceof NotFoundException) {
this.logger.info('Defender not found', error)
} else throw error
} else {
throw error
}
}

// If a defender doesn't have any active cases, we look them up
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict'

module.exports = {
up(queryInterface) {
return Promise.all([
queryInterface.removeConstraint('user', 'user_national_id_key'),
queryInterface.addConstraint('user', {
fields: ['national_id', 'institution_id'],
type: 'unique',
name: 'unique_national_id_per_institution',
}),
])
},

down(queryInterface, Sequelize) {
return Promise.all([
queryInterface.changeColumn('user', 'national_id', {
type: Sequelize.STRING,
unique: true,
allowNull: false,
}),
queryInterface.removeConstraint(
'user',
'unique_national_id_per_institution',
),
])
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -331,17 +331,16 @@ export class InternalCaseService {
}

async create(caseToCreate: InternalCreateCaseDto): Promise<Case> {
const creator = await this.userService
const users = await this.userService
.findByNationalId(caseToCreate.prosecutorNationalId)
.catch(() => undefined)

if (!creator) {
throw new BadRequestException('Creating user not found')
}
// TODO: Sync with LÖKE so we can select the correct user
const creator = users?.find((user) => isProsecutionUser(user))

if (!isProsecutionUser(creator)) {
if (!creator) {
throw new BadRequestException(
'Creating user is not registered as a prosecution user',
'Creating user not found or is not registered as a prosecution user',
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])
const mockCreate = mockCaseModel.create as jest.Mock
mockCreate.mockResolvedValueOnce(createdCase)
const mockDefendantCreate =
Expand Down Expand Up @@ -215,7 +215,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])

then = await givenWhenThen(caseToCreate)
})
Expand Down Expand Up @@ -244,7 +244,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])

await givenWhenThen({
...caseToCreate,
Expand Down Expand Up @@ -285,7 +285,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])

await givenWhenThen({ ...caseToCreate, isHeightenedSecurityLevel: true })
})
Expand Down Expand Up @@ -338,7 +338,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])

then = await givenWhenThen(caseToCreate)
})
Expand All @@ -364,7 +364,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])
const mockCreate = mockCaseModel.create as jest.Mock
mockCreate.mockResolvedValueOnce(createdCase)

Expand Down Expand Up @@ -392,7 +392,7 @@ describe('InternalCaseController - Create', () => {

beforeEach(async () => {
const mockFindByNationalId = mockUserService.findByNationalId as jest.Mock
mockFindByNationalId.mockResolvedValueOnce(user)
mockFindByNationalId.mockResolvedValueOnce([user])
const mockCreate = mockCaseModel.create as jest.Mock
mockCreate.mockResolvedValueOnce(createdCase)
const mockDefendantCreate =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,40 +51,43 @@ describe('UserController - Get by national id', () => {
})

it('should return the user', () => {
expect(then.result).toEqual({
id: '8f8f6522-95c8-46dd-98ef-cbc198544871',
nationalId: '3333333333',
name: 'Addi Admin',
title: 'notendaumsjón',
created: date,
modified: date,
mobileNumber: '',
email: '',
role: UserRole.ADMIN,
active: true,
canConfirmIndictment: false,
})
expect(then.result).toEqual([
{
id: '8f8f6522-95c8-46dd-98ef-cbc198544871',
nationalId: '3333333333',
name: 'Addi Admin',
title: 'notendaumsjón',
created: date,
modified: date,
mobileNumber: '',
email: '',
role: UserRole.ADMIN,
active: true,
canConfirmIndictment: false,
},
])
})
})

describe('user found', () => {
const nationalId = uuid()
const user = { id: uuid() } as User
const user1 = { id: uuid() } as User
const user2 = { id: uuid() } as User
let then: Then

beforeEach(async () => {
const mockFindOne = mockUserModel.findOne as jest.Mock
mockFindOne.mockResolvedValueOnce(user)
const mockFindOne = mockUserModel.findAll as jest.Mock
mockFindOne.mockResolvedValueOnce([user1, user2])

then = await givenWhenThen(nationalId)
})

it('should return the user', () => {
expect(mockUserModel.findOne).toHaveBeenCalledWith({
expect(mockUserModel.findAll).toHaveBeenCalledWith({
where: { nationalId, active: true },
include: [{ model: Institution, as: 'institution' }],
})
expect(then.result).toBe(user)
expect(then.result).toEqual([user1, user2])
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class UserController {
type: User,
description: 'Gets an existing user by national id',
})
getByNationalId(@Query('nationalId') nationalId: string): Promise<User> {
getByNationalId(@Query('nationalId') nationalId: string): Promise<User[]> {
this.logger.debug('Getting a user by national id')

return this.userService.findByNationalId(nationalId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class User extends Model {
@ApiProperty({ type: Date })
modified!: Date

@Column({ type: DataType.STRING, allowNull: false, unique: true })
@Column({ type: DataType.STRING, allowNull: false })
@ApiProperty({ type: String })
nationalId!: string

Expand Down
30 changes: 16 additions & 14 deletions apps/judicial-system/backend/src/app/modules/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class UserService {
return user
}

async findByNationalId(nationalId: string): Promise<User> {
async findByNationalId(nationalId: string): Promise<User[]> {
// First check if the user is an admin
try {
const admin = this.config.adminUsers.find(
Expand All @@ -64,32 +64,34 @@ export class UserService {
if (admin) {
// Default values are necessary because most of the fields are required
// all the way up to the client. Consider refactoring this.
return {
created: nowFactory(),
modified: nowFactory(),
mobileNumber: '',
email: '',
role: UserRole.ADMIN,
active: true,
canConfirmIndictment: false,
...admin,
} as User
return [
{
created: nowFactory(),
modified: nowFactory(),
mobileNumber: '',
email: '',
role: UserRole.ADMIN,
active: true,
canConfirmIndictment: false,
...admin,
} as User,
]
}
} catch (error) {
// Tolerate failure, but log error
this.logger.error('Failed to parse admin users', { error })
}

const user = await this.userModel.findOne({
const users = await this.userModel.findAll({
where: { nationalId, active: true },
include: [{ model: Institution, as: 'institution' }],
})

if (!user) {
if (!users || users.length === 0) {
throw new NotFoundException('User does not exist')
}

return user
return users
}

async create(userToCreate: CreateUserDto): Promise<User> {
Expand Down
Loading