Skip to content
Merged

0.7.0 #157

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9ab8bce
Merge pull request #146 from iqb-berlin/main
jurei733 Jun 18, 2025
166ba25
Delete workspace with all related files and results
jurei733 Jun 19, 2025
dc8e13f
Use queryParams to deleteWorkspace
jurei733 Jun 20, 2025
4ccaef6
Prevent removal of all id or user id with custom exceptions
jurei733 Jun 20, 2025
01b6dd8
Update to latest Jest snapshotFormat
jurei733 Jun 20, 2025
6d2ce31
Add test-files pagination and filtering
jurei733 Jun 21, 2025
21f2c6a
Improve of view of not coded responses
jurei733 Jun 21, 2025
2c0a9fc
Show unit and scheme info in coding management
jurei733 Jun 22, 2025
bec4e8b
Display file content
jurei733 Jun 23, 2025
ec6af09
Use another algorithm to extract unit definition variable info
jurei733 Jun 23, 2025
de442dc
Fix filter text search input in test-files component
jurei733 Jun 23, 2025
1d80997
Select the highest minor player version automatically
jurei733 Jun 24, 2025
f197f41
Implement search filtering for test-results in the backend
jurei733 Jun 24, 2025
ccd29b1
Implement search filtering for test-results in the backend
jurei733 Jun 24, 2025
4771ac8
Add unit tags to booklet response
jurei733 Jun 25, 2025
2048855
Search for responses
jurei733 Jun 25, 2025
5c29944
Delete searched responses or units
jurei733 Jun 25, 2025
2878b24
Improve ui for app-info component
jurei733 Jun 25, 2025
9de9c22
Set version to 0.7.0
jurei733 Jun 25, 2025
27984c5
Merge branch 'develop' into 0.7.0
jurei733 Jun 25, 2025
850312b
Fix double definitions
jurei733 Jun 25, 2025
ba9f44b
Merge pull request #156 from iqb-berlin/0.7.0
jurei733 Jun 25, 2025
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
11 changes: 6 additions & 5 deletions apps/backend/src/app/admin/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
Body,
Controller, Delete, Get, Param, Patch, Post, UseGuards
Controller, Delete, Get, Param, Patch, Post, Query, Req, UseGuards
} from '@nestjs/common';
import {
ApiBadRequestResponse, ApiBearerAuth, ApiBody, ApiCreatedResponse, ApiMethodNotAllowedResponse,
Expand Down Expand Up @@ -120,13 +120,14 @@ export class UsersController {
@ApiBadRequestResponse({ description: 'Invalid user IDs' })
@ApiNotFoundResponse({ description: 'One or more users not found' })
@ApiTags('admin users')
async remove(@Param('ids') ids: string): Promise<void> {
async remove(@Param('ids') ids: string, @Req() req): Promise<void> {
const idsAsNumberArray: number[] = [];
ids.split(';').forEach(s => idsAsNumberArray.push(parseInt(s, 10)));
return this.usersService.remove(idsAsNumberArray);
return this.usersService.removeIds(idsAsNumberArray, req.user.id);
}

@Delete()
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({
summary: 'Delete users by query',
Expand All @@ -144,8 +145,8 @@ export class UsersController {
@ApiBadRequestResponse({ description: 'Invalid user IDs' })
@ApiNotFoundResponse({ description: 'One or more users not found' })
@ApiMethodNotAllowedResponse({ description: 'Active admin user must not be deleted' })
async removeIds(ids: number[]): Promise<void> {
return this.usersService.removeIds(ids);
async removeIds(@Query('id') ids: number[], @Req() req): Promise<void> {
return this.usersService.removeIds(ids, req.user.id);
}

@Post(':userId/workspaces')
Expand Down
137 changes: 134 additions & 3 deletions apps/backend/src/app/admin/workspace/workspace-files.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
BadRequestException,
Controller,
Delete,
Get, InternalServerErrorException, Param, Post, Query, UseGuards, UseInterceptors, UploadedFiles
Get, InternalServerErrorException, NotFoundException, Param, Post, Query, UseGuards, UseInterceptors, UploadedFiles
} from '@nestjs/common';
import {
ApiBadRequestResponse,
Expand Down Expand Up @@ -47,6 +47,24 @@ export class WorkspaceFilesController {
description: 'Number of items per page',
type: Number
})
@ApiQuery({
name: 'fileType',
required: false,
description: 'Filter by file type',
type: String
})
@ApiQuery({
name: 'fileSize',
required: false,
description: 'Filter by file size range (e.g. 0-10KB, 10KB-100KB, 100KB-1MB, 1MB-10MB, 10MB+)',
type: String
})
@ApiQuery({
name: 'searchText',
required: false,
description: 'Filter by search text (filename, type, date)',
type: String
})
@ApiOkResponse({
description: 'Files retrieved successfully.',
schema: {
Expand All @@ -69,15 +87,20 @@ export class WorkspaceFilesController {
async findFiles(
@Param('workspace_id') workspace_id: number,
@Query('page') page: number = 1,
@Query('limit') limit: number = 20
@Query('limit') limit: number = 20,
@Query('fileType') fileType?: string,
@Query('fileSize') fileSize?: string,
@Query('searchText') searchText?: string
): Promise<{ data: FilesDto[]; total: number; page: number; limit: number }> {
if (!workspace_id || workspace_id <= 0) {
throw new BadRequestException(
'Invalid workspace ID. Please provide a valid ID.'
);
}
try {
const [files, total] = await this.workspaceFilesService.findFiles(workspace_id, { page, limit });
const [files, total] = await this.workspaceFilesService.findFiles(workspace_id, {
page, limit, fileType, fileSize, searchText
});
return {
data: files,
total,
Expand Down Expand Up @@ -184,4 +207,112 @@ export class WorkspaceFilesController {
throw new InternalServerErrorException('Unable to download the file. Please try again later.');
}
}

@Get(':workspace_id/unit/:unit_id/content')
@ApiTags('admin workspace')
@ApiBearerAuth()
@ApiOperation({ summary: 'Get unit XML content', description: 'Retrieves the XML content of a unit file' })
@ApiParam({
name: 'workspace_id',
type: Number,
required: true,
description: 'The unique ID of the workspace'
})
@ApiParam({
name: 'unit_id',
type: Number,
required: true,
description: 'The unique ID of the unit'
})
@ApiOkResponse({
description: 'Unit XML content retrieved successfully',
schema: {
type: 'object',
properties: {
content: { type: 'string' }
}
}
})
@ApiNotFoundResponse({
description: 'Unit not found'
})
@ApiBadRequestResponse({
description: 'Invalid workspace ID or unit ID'
})
@UseGuards(JwtAuthGuard, WorkspaceGuard)
async getUnitContent(
@Param('workspace_id') workspace_id: number,
@Param('unit_id') unit_id: number
): Promise<{ content: string }> {
if (!workspace_id || workspace_id <= 0) {
throw new BadRequestException('Invalid workspace ID. Please provide a valid ID.');
}
if (!unit_id || unit_id <= 0) {
throw new BadRequestException('Invalid unit ID. Please provide a valid ID.');
}

try {
const content = await this.workspaceFilesService.getUnitContent(workspace_id, unit_id);
return { content };
} catch (error) {
if (error.message.includes('not found')) {
throw new NotFoundException(`Unit with ID ${unit_id} not found in workspace ${workspace_id}`);
}
throw new InternalServerErrorException(`Error retrieving unit content: ${error.message}`);
}
}

@Get(':workspace_id/files/coding-scheme/:coding_scheme_ref')
@ApiTags('admin workspace')
@ApiBearerAuth()
@ApiOperation({ summary: 'Get coding scheme file', description: 'Retrieves a coding scheme file by its reference name' })
@ApiParam({
name: 'workspace_id',
type: Number,
required: true,
description: 'The unique ID of the workspace'
})
@ApiParam({
name: 'coding_scheme_ref',
type: String,
required: true,
description: 'The reference name of the coding scheme'
})
@ApiOkResponse({
description: 'Coding scheme file retrieved successfully',
type: FileDownloadDto
})
@ApiNotFoundResponse({
description: 'Coding scheme file not found'
})
@ApiBadRequestResponse({
description: 'Invalid workspace ID or coding scheme reference'
})
@UseGuards(JwtAuthGuard, WorkspaceGuard)
async getCodingSchemeFile(
@Param('workspace_id') workspace_id: number,
@Param('coding_scheme_ref') coding_scheme_ref: string
): Promise<FileDownloadDto> {
if (!workspace_id || workspace_id <= 0) {
throw new BadRequestException('Invalid workspace ID. Please provide a valid ID.');
}
if (!coding_scheme_ref) {
throw new BadRequestException('Invalid coding scheme reference. Please provide a valid reference.');
}

try {
const codingSchemeFile = await this.workspaceFilesService.getCodingSchemeByRef(workspace_id, coding_scheme_ref);

if (!codingSchemeFile) {
throw new NotFoundException(`Coding scheme file '${coding_scheme_ref}' not found in workspace ${workspace_id}`);
}

return codingSchemeFile;
} catch (error) {
if (error.status === 404) {
throw error;
}
throw new InternalServerErrorException(`Error retrieving coding scheme file: ${error.message}`);
}
}
}
Loading