diff --git a/backend/src/api/members/controllers/groups.controller.ts b/backend/src/api/members/controllers/groups.controller.ts index ab93311c..0abb6d3c 100644 --- a/backend/src/api/members/controllers/groups.controller.ts +++ b/backend/src/api/members/controllers/groups.controller.ts @@ -8,35 +8,30 @@ 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, - ) {} + 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 { + return this.groups.getGroups(query); } @Post() @@ -44,14 +39,14 @@ export class GroupsController { @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); @@ -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 { - 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); } } diff --git a/backend/src/api/members/dto/group.dto.ts b/backend/src/api/members/dto/group.dto.ts index fba02313..78d666a4 100644 --- a/backend/src/api/members/dto/group.dto.ts +++ b/backend/src/api/members/dto/group.dto.ts @@ -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; @@ -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 { @ApiProperty() @IsString() shortName!: string; @ApiPropertyOptional({ type: "string" }) @IsString() @IsOptional() name!: string | null; diff --git a/backend/src/models/members/repositories/groups.repository.ts b/backend/src/models/members/repositories/groups.repository.ts index c3096c9f..a9686e29 100644 --- a/backend/src/models/members/repositories/groups.repository.ts +++ b/backend/src/models/members/repositories/groups.repository.ts @@ -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) {} - 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) { diff --git a/frontend/src/app/api/sdk/api.ts b/frontend/src/app/api/sdk/api.ts index 29726c05..a56f48a5 100644 --- a/frontend/src/app/api/sdk/api.ts +++ b/frontend/src/app/api/sdk/api.ts @@ -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). @@ -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 => { + listGroups: async (active?: boolean, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/groups`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -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); @@ -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>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.listGroups(options); + async listGroups(active?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listGroups(active, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -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> { - return localVarFp.listGroups(options).then((request) => request(axios, basePath)); + listGroups(requestParameters: MembersApiListGroupsRequest = {}, options?: AxiosRequestConfig): AxiosPromise> { + return localVarFp.listGroups(requestParameters.active, options).then((request) => request(axios, basePath)); }, /** * @@ -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. @@ -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)); } /** diff --git a/frontend/src/app/api/sdk/base.ts b/frontend/src/app/api/sdk/base.ts index 6d43cf47..e1a119dc 100644 --- a/frontend/src/app/api/sdk/base.ts +++ b/frontend/src/app/api/sdk/base.ts @@ -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). diff --git a/frontend/src/app/api/sdk/common.ts b/frontend/src/app/api/sdk/common.ts index 21ddf752..3a2f9259 100644 --- a/frontend/src/app/api/sdk/common.ts +++ b/frontend/src/app/api/sdk/common.ts @@ -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). diff --git a/frontend/src/app/api/sdk/configuration.ts b/frontend/src/app/api/sdk/configuration.ts index 1ea371a1..b339f789 100644 --- a/frontend/src/app/api/sdk/configuration.ts +++ b/frontend/src/app/api/sdk/configuration.ts @@ -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). diff --git a/frontend/src/app/api/sdk/index.ts b/frontend/src/app/api/sdk/index.ts index 4a5f058e..55b4487c 100644 --- a/frontend/src/app/api/sdk/index.ts +++ b/frontend/src/app/api/sdk/index.ts @@ -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). diff --git a/frontend/src/app/modules/members/components/member-info/member-info.component.html b/frontend/src/app/modules/members/components/member-info/member-info.component.html index 07008d39..8afe1b0c 100644 --- a/frontend/src/app/modules/members/components/member-info/member-info.component.html +++ b/frontend/src/app/modules/members/components/member-info/member-info.component.html @@ -1,38 +1,48 @@ -

Základní informace

+

+ Základní informace + Upravit +

- + Jméno: {{ member.firstName || "-" }} {{ member.lastName || "-" }} - + - + Přezdívka: {{ member.nickname || "-" }} - + - + Datum narození: {{ member.birthday ? (member.birthday | date: "d. M. y") : "-" }} - +

Členství ve skupině

- - Aktivní člen: + + Aktivní: {{ member.active === undefined ? "-" : member.active ? "Ano" : "Ne" }} - + - + + Role: + + {{ member | member: "role" || "-" }} + + + + Oddíl - +