Skip to content

Commit

Permalink
feat: membership edits
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Kopeček committed Feb 3, 2024
1 parent 788916a commit b6a22cc
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 45 deletions.
27 changes: 11 additions & 16 deletions backend/src/api/members/controllers/groups.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,45 @@ import {
Param,
Post,
Put,
Query,
Req,
UseGuards,
} from "@nestjs/common";
import { ApiResponse, ApiTags } from "@nestjs/swagger";
import { InjectRepository } from "@nestjs/typeorm";
import { Request } from "express";
import { AcController, AcLinks, WithLinks } from "src/access-control/access-control-lib";
import { UserGuard } from "src/auth/guards/user.guard";
import { Group } from "src/models/members/entities/group.entity";
import { GroupsRepository } from "src/models/members/repositories/groups.repository";
import { Repository } from "typeorm";
import { GroupCreateRoute, GroupDeleteRoute, GroupEditRoute, GroupListRoute, GroupReadRoute } from "../acl/groups.acl";
import { CreateGroupBody, GroupResponse, UpdateGroupBody } from "../dto/group.dto";
import { CreateGroupBody, GroupResponse, ListGroupsQuery, UpdateGroupBody } from "../dto/group.dto";

@Controller("groups")
@UseGuards(UserGuard)
@AcController()
@ApiTags("Members")
export class GroupsController {
constructor(
private groupsService: GroupsRepository,
@InjectRepository(Group) private groupsRepository: Repository<Group>,
) {}
constructor(private groups: GroupsRepository) {}

@Get()
@AcLinks(GroupListRoute)
@ApiResponse({ type: WithLinks(GroupResponse), isArray: true })
async listGroups(@Req() req: Request) {
return this.groupsRepository.createQueryBuilder().where(GroupListRoute.canWhere(req)).getMany();
async listGroups(@Req() req: Request, @Query() query: ListGroupsQuery): Promise<GroupResponse[]> {
return this.groups.getGroups(query);
}

@Post()
@AcLinks(GroupCreateRoute)
@ApiResponse({ status: HttpStatus.CREATED, type: WithLinks(GroupResponse) })
async createGroup(@Req() req: Request, @Body() groupData: CreateGroupBody) {
GroupCreateRoute.canOrThrow(req, undefined);
return this.groupsService.createGroup(groupData);
return this.groups.createGroup(groupData);
}

@Get(":id")
@AcLinks(GroupReadRoute)
@ApiResponse({ type: WithLinks(GroupResponse) })
async getGroup(@Param("id") id: number, @Req() req: Request) {
const group = await this.groupsService.getGroup(id);
const group = await this.groups.getGroup(id);
if (!group) throw new NotFoundException();

GroupReadRoute.canOrThrow(req, group);
Expand All @@ -63,22 +58,22 @@ export class GroupsController {
@AcLinks(GroupEditRoute)
@ApiResponse({ status: HttpStatus.OK })
async updateGroup(@Param("id") id: number, @Req() req: Request, @Body() body: UpdateGroupBody) {
const group = await this.groupsService.getGroup(id);
const group = await this.groups.getGroup(id);
if (!group) throw new NotFoundException();

GroupEditRoute.canOrThrow(req, group);

await this.groupsService.updateGroup(id, req.body);
await this.groups.updateGroup(id, req.body);
}

@Delete(":id")
@AcLinks(GroupDeleteRoute)
async deleteGroup(@Param("id") id: number, @Req() req: Request): Promise<void> {
const group = await this.groupsService.getGroup(id);
const group = await this.groups.getGroup(id);
if (!group) throw new NotFoundException();

GroupDeleteRoute.canOrThrow(req, group);

await this.groupsService.deleteGroup(id);
await this.groups.deleteGroup(id);
}
}
5 changes: 5 additions & 0 deletions backend/src/api/members/dto/group.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { IsOptional, IsString } from "class-validator";
import { Group } from "src/models/members/entities/group.entity";
import { EnsureBoolean } from "src/utilities/validation";

export class GroupResponse implements Group {
@ApiProperty() id!: number;
Expand All @@ -12,6 +13,10 @@ export class GroupResponse implements Group {
@ApiPropertyOptional({ type: "string" }) deletedAt!: string | null;
}

export class ListGroupsQuery {
@ApiPropertyOptional() @EnsureBoolean() @IsOptional() active?: boolean;
}

export class CreateGroupBody implements Pick<Group, "shortName" | "name"> {
@ApiProperty() @IsString() shortName!: string;
@ApiPropertyOptional({ type: "string" }) @IsString() @IsOptional() name!: string | null;
Expand Down
13 changes: 10 additions & 3 deletions backend/src/models/members/repositories/groups.repository.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { FindManyOptions, FindOneOptions, Repository } from "typeorm";
import { FindOneOptions, Repository } from "typeorm";
import { Group } from "../entities/group.entity";

export interface GetGroupsOptions {
active?: boolean;
}

@Injectable()
export class GroupsRepository {
constructor(@InjectRepository(Group) private groupsRepository: Repository<Group>) {}

async getGroups(options?: FindManyOptions) {
return this.groupsRepository.find(options);
async getGroups(options: GetGroupsOptions = {}) {
return this.groupsRepository.find({
order: { shortName: "ASC" },
where: { active: options.active },
});
}

async getGroup(id: number, options?: FindOneOptions<Group>) {
Expand Down
52 changes: 44 additions & 8 deletions frontend/src/app/api/sdk/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Bošán - Interní sekce
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: v4.0.0-rc.7
* The version of the OpenAPI document: v4.0.0-rc.8
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down Expand Up @@ -6196,10 +6196,11 @@ export const MembersApiAxiosParamCreator = function (configuration?: Configurati
},
/**
*
* @param {boolean} [active]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listGroups: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
listGroups: async (active?: boolean, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/groups`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
Expand All @@ -6212,6 +6213,10 @@ export const MembersApiAxiosParamCreator = function (configuration?: Configurati
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;

if (active !== undefined) {
localVarQueryParameter['active'] = active;
}



setSearchParams(localVarUrlObj, localVarQueryParameter);
Expand Down Expand Up @@ -6584,11 +6589,12 @@ export const MembersApiFp = function(configuration?: Configuration) {
},
/**
*
* @param {boolean} [active]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listGroups(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<GroupResponseWithLinks>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listGroups(options);
async listGroups(active?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<GroupResponseWithLinks>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listGroups(active, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
Expand Down Expand Up @@ -6771,11 +6777,12 @@ export const MembersApiFactory = function (configuration?: Configuration, basePa
},
/**
*
* @param {MembersApiListGroupsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listGroups(options?: AxiosRequestConfig): AxiosPromise<Array<GroupResponseWithLinks>> {
return localVarFp.listGroups(options).then((request) => request(axios, basePath));
listGroups(requestParameters: MembersApiListGroupsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<GroupResponseWithLinks>> {
return localVarFp.listGroups(requestParameters.active, options).then((request) => request(axios, basePath));
},
/**
*
Expand Down Expand Up @@ -7103,6 +7110,34 @@ export interface MembersApiListContactsRequest {
}


/**
* Request parameters for listGroups operation in MembersApi.
* @export
* @interface MembersApiListGroupsRequest
*/
export interface MembersApiListGroupsRequest {
/**
*
* @type {boolean}
* @memberof MembersApiListGroups
*/
readonly active?: boolean
}


/**
* Query parameters for listGroups operation in MembersApi.
* @export
* @interface MembersApiListGroupsQueryParams
*/
export interface MembersApiListGroupsQueryParams {
/**
*
* @type {boolean}
* @memberof MembersApiListGroups
*/
active?: boolean
}

/**
* Request parameters for listMembers operation in MembersApi.
Expand Down Expand Up @@ -7439,12 +7474,13 @@ export class MembersApi extends BaseAPI {

/**
*
* @param {MembersApiListGroupsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof MembersApi
*/
public listGroups(options?: AxiosRequestConfig) {
return MembersApiFp(this.configuration).listGroups(options).then((request) => request(this.axios, this.basePath));
public listGroups(queryParams: MembersApiListGroupsQueryParams = {}, options?: AxiosRequestConfig) {
return MembersApiFp(this.configuration).listGroups(queryParams.active, options).then((request) => request(this.axios, this.basePath));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/api/sdk/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Bošán - Interní sekce
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: v4.0.0-rc.7
* The version of the OpenAPI document: v4.0.0-rc.8
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/api/sdk/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Bošán - Interní sekce
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: v4.0.0-rc.7
* The version of the OpenAPI document: v4.0.0-rc.8
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/api/sdk/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Bošán - Interní sekce
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: v4.0.0-rc.7
* The version of the OpenAPI document: v4.0.0-rc.8
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/api/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Bošán - Interní sekce
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: v4.0.0-rc.7
* The version of the OpenAPI document: v4.0.0-rc.8
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
<h4>Základní informace</h4>
<h4 class="d-flex justify-content-between">
Základní informace
<bo-edit-button slot="end" (click)="openBasicInfoForm()" class="float-end">Upravit</bo-edit-button>
</h4>
<ion-list *ngIf="member" class="selectable">
<ion-item [button]="true" [detail]="false">
<ion-item>
<ion-label>Jméno:</ion-label>
<ion-label>{{ member.firstName || "-" }} {{ member.lastName || "-" }}</ion-label>
<bo-edit-button slot="end"></bo-edit-button>
<bo-copy-button slot="end" [text]="member.firstName + ' ' + member.lastName"></bo-copy-button>
</ion-item>

<ion-item [button]="true" [detail]="false">
<ion-item>
<ion-label>Přezdívka:</ion-label>
<ion-label>{{ member.nickname || "-" }}</ion-label>
<bo-edit-button slot="end"></bo-edit-button>
<bo-copy-button slot="end" [text]="member.nickname"></bo-copy-button>
</ion-item>

<ion-item [button]="true" [detail]="false">
<ion-item>
<ion-label>Datum narození:</ion-label>
<ion-label>{{ member.birthday ? (member.birthday | date: "d. M. y") : "-" }}</ion-label>
<bo-edit-button slot="end"></bo-edit-button>
<bo-copy-button slot="end" [text]="member.birthday | date: 'd. M. y'"></bo-copy-button>
</ion-item>
</ion-list>

<h4 class="mt-4">Členství ve skupině</h4>
<ion-list *ngIf="member" class="selectable">
<ion-item [button]="true" [detail]="false">
<ion-label>Aktivní člen:</ion-label>
<ion-item>
<ion-label>Aktivní:</ion-label>
<ion-label>{{ member.active === undefined ? "-" : member.active ? "Ano" : "Ne" }}</ion-label>
<bo-edit-button slot="end"></bo-edit-button>
<bo-edit-button slot="end" (click)="openMembershipChangeForm()"></bo-edit-button>
</ion-item>

<ion-item [button]="true" [detail]="false">
<ion-item>
<ion-label>Role:</ion-label>

<ion-label>{{ member | member: "role" || "-" }}</ion-label>
<bo-edit-button slot="end" (click)="openRoleChangeForm()"></bo-edit-button>
</ion-item>

<ion-item>
<ion-label>Oddíl</ion-label>
<ion-label>
<bo-group-badge [groupId]="member.groupId"></bo-group-badge>
</ion-label>
<bo-edit-button slot="end"></bo-edit-button>
<bo-edit-button slot="end" (click)="openGroupChangeForm()"></bo-edit-button>
</ion-item>

<!-- <ion-item [button]="true" [detail]="false">
Expand Down
Loading

0 comments on commit b6a22cc

Please sign in to comment.