Skip to content

Commit fd99aea

Browse files
authored
Merge pull request #982 from joshunrau/dev
2 parents e7e9bc3 + 1c55b55 commit fd99aea

30 files changed

Lines changed: 136 additions & 82 deletions

File tree

apps/api/prisma/schema.prisma

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ model UserModel {
164164
lastName String
165165
password String
166166
username String
167+
sex Sex?
168+
dateOfBirth DateTime? @db.Date
167169
}
168170

169171
enum SessionType {

apps/api/src/ability/__tests__/ability.factory.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ describe('AbilityFactory', () => {
1717
userModelStub = {
1818
basePermissionLevel: null,
1919
createdAt: new Date(),
20+
dateOfBirth: null,
2021
firstName: 'Jane',
2122
groupIds: [],
2223
id: '12345',
2324
lastName: 'Doe',
2425
password: 'Password123',
26+
sex: null,
2527
updatedAt: new Date(),
2628
username: 'user'
2729
};
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ValidationSchema } from '@douglasneuroinformatics/libnest/core';
22
import { PartialType } from '@nestjs/swagger';
3-
import { $UpdateGroupData, type GroupSettings } from '@opendatacapture/schemas/group';
3+
import { $UpdateGroupData, type GroupSettings, type GroupType } from '@opendatacapture/schemas/group';
44

55
import { CreateGroupDto } from './create-group.dto';
66

@@ -9,4 +9,5 @@ export class UpdateGroupDto extends PartialType(CreateGroupDto) {
99
accessibleInstrumentIds?: string[];
1010
override name?: string;
1111
settings?: GroupSettings;
12+
override type?: GroupType;
1213
}

apps/api/src/groups/groups.service.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
2+
import type { Prisma } from '@prisma/client';
23

34
import { accessibleQuery } from '@/ability/ability.utils';
45
import type { EntityOperationOptions } from '@/core/types';
@@ -61,6 +62,15 @@ export class GroupsService {
6162
{ accessibleInstrumentIds, ...data }: UpdateGroupDto,
6263
{ ability }: EntityOperationOptions = {}
6364
) {
65+
const where: Prisma.GroupModelWhereInput = { AND: [accessibleQuery(ability, 'update', 'Group')], id };
66+
const group = await this.groupModel.findFirst({ where });
67+
if (!group) {
68+
throw new NotFoundException(`Failed to find group with ID: ${id}`);
69+
}
70+
const exists = typeof data.name === 'string' && (await this.groupModel.exists({ name: group.name }));
71+
if (exists) {
72+
throw new ConflictException(`Group with name '${group.name}' already exists!`);
73+
}
6474
return this.groupModel.update({
6575
data: {
6676
accessibleInstruments: accessibleInstrumentIds

apps/api/src/users/dto/create-user.dto.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { ValidationSchema } from '@douglasneuroinformatics/libnest/core';
22
import { estimatePasswordStrength } from '@douglasneuroinformatics/libpasswd';
33
import { ApiProperty } from '@nestjs/swagger';
4+
import type { Sex } from '@opendatacapture/schemas/subject';
45
import { $CreateUserData } from '@opendatacapture/schemas/user';
5-
import type { BasePermissionLevel } from '@opendatacapture/schemas/user';
6+
import type { BasePermissionLevel, CreateUserData } from '@opendatacapture/schemas/user';
67
import { z } from 'zod';
78

89
@ValidationSchema(
@@ -20,14 +21,17 @@ import { z } from 'zod';
2021
})
2122
})
2223
)
23-
export class CreateUserDto {
24+
export class CreateUserDto implements CreateUserData {
2425
@ApiProperty({
2526
description: "Determines the user's base permissions, which may later be modified by an admin",
2627
enum: ['ADMIN', 'GROUP_MANAGER', 'STANDARD'] satisfies BasePermissionLevel[],
2728
type: String
2829
})
2930
basePermissionLevel: BasePermissionLevel | null;
3031

32+
@ApiProperty({ description: 'Date of Birth' })
33+
dateOfBirth?: Date;
34+
3135
@ApiProperty({ description: 'First Name' })
3236
firstName: string;
3337

@@ -44,6 +48,10 @@ export class CreateUserDto {
4448
})
4549
password: string;
4650

51+
@ApiProperty({ description: 'Sex at Birth' })
52+
@ApiProperty()
53+
sex?: Sex;
54+
4755
@ApiProperty({
4856
description: 'A unique descriptive name associated with this user',
4957
example: 'JaneDoeMemoryClinic'

apps/api/src/users/users.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class UsersService {
3030

3131
/** Adds a new user to the database with default permissions, verifying the provided groups exist */
3232
async create(
33-
{ basePermissionLevel, firstName, groupIds, lastName, password, username }: CreateUserDto,
33+
{ basePermissionLevel, dateOfBirth, firstName, groupIds, lastName, password, sex, username }: CreateUserDto,
3434
options?: EntityOperationOptions
3535
) {
3636
if (await this.userModel.exists({ username })) {
@@ -50,12 +50,14 @@ export class UsersService {
5050
return this.userModel.create({
5151
data: {
5252
basePermissionLevel,
53+
dateOfBirth,
5354
firstName,
5455
groups: {
5556
connect: groupIds.map((id) => ({ id }))
5657
},
5758
lastName,
5859
password: hashedPassword,
60+
sex,
5961
username: username
6062
}
6163
});

apps/web/src/components/IdentificationForm/IdentificationForm.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type IdentificationFormProps = {
1313
onSubmit: (data: { id: string }) => Promisable<void>;
1414
};
1515

16+
// eslint-disable-next-line max-lines-per-function
1617
export const IdentificationForm = ({ onSubmit }: IdentificationFormProps) => {
1718
const currentGroup = useAppStore((store) => store.currentGroup);
1819
const { t } = useTranslation();

apps/web/src/components/Sidebar/Sidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useAppStore } from '@/store';
1313
import { NavButton } from '../NavButton';
1414
import { UserDropup } from '../UserDropup';
1515

16+
// eslint-disable-next-line max-lines-per-function
1617
export const Sidebar = () => {
1718
const navItems = useNavItems();
1819
const currentSession = useAppStore((store) => store.currentSession);

apps/web/src/features/admin/hooks/useGroupsQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { $Group } from '@opendatacapture/schemas/group';
2-
import { useSuspenseQuery } from '@tanstack/react-query';
2+
import { useQuery } from '@tanstack/react-query';
33
import axios from 'axios';
44

55
export function useGroupsQuery() {
6-
return useSuspenseQuery({
6+
return useQuery({
77
queryFn: async () => {
88
const response = await axios.get('/v1/groups');
99
return $Group.array().parse(response.data);

apps/web/src/features/admin/hooks/useUsersQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { $User } from '@opendatacapture/schemas/user';
2-
import { useSuspenseQuery } from '@tanstack/react-query';
2+
import { useQuery } from '@tanstack/react-query';
33
import axios from 'axios';
44

55
export function useUsersQuery() {
6-
return useSuspenseQuery({
6+
return useQuery({
77
queryFn: async () => {
88
const response = await axios.get('/v1/users');
99
return $User.array().parse(response.data);

0 commit comments

Comments
 (0)