Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6e86003
add research group component without logic
Bofan-Zhu Sep 2, 2025
6c9fd52
adjust styling
Bofan-Zhu Sep 2, 2025
7455a5a
Merge branch 'main' into 608-implement-research-group-page
Bofan-Zhu Sep 7, 2025
2e9e383
add functionality
Bofan-Zhu Sep 7, 2025
ef22c78
remove unnecessary null checks and clean up dto
Bofan-Zhu Sep 7, 2025
14e9905
clean up
Bofan-Zhu Sep 7, 2025
a7defbf
reduce dto
Bofan-Zhu Sep 7, 2025
c2fbd58
add non-empty validation and exception to dto
Bofan-Zhu Sep 7, 2025
1f58e16
remove transactional
Bofan-Zhu Sep 7, 2025
61803e6
add translate directive
Bofan-Zhu Sep 7, 2025
d1493b9
remove unnecessary fontawesome import
Bofan-Zhu Sep 7, 2025
61b3424
fix types and improve naming of labels
Bofan-Zhu Sep 7, 2025
0d5c362
add validation to required form fields
Bofan-Zhu Sep 8, 2025
d7ecd17
remove console logs
Bofan-Zhu Sep 8, 2025
cb57122
update dto constraints
Bofan-Zhu Sep 8, 2025
29da683
restrain update rights
Bofan-Zhu Sep 8, 2025
36c8902
add missing form field and remove id from dto
Bofan-Zhu Sep 8, 2025
9bee41d
remove border and divider
Bofan-Zhu Sep 8, 2025
11f67a9
add scss class
Bofan-Zhu Sep 8, 2025
6f42666
add toast translations
Bofan-Zhu Sep 8, 2025
1084e21
add valid check
Bofan-Zhu Sep 8, 2025
42ec5c9
change sidebar icon, adjust translation
Bofan-Zhu Sep 8, 2025
eed83b6
change tab title
Bofan-Zhu Sep 8, 2025
82df466
add email form validation
Bofan-Zhu Sep 8, 2025
f36dce6
Resolve merge conflict in ResearchGroupService.java
Bofan-Zhu Sep 8, 2025
06f1274
re generate openapi
Bofan-Zhu Sep 8, 2025
64d61c4
Merge branch 'main' into 608-implement-research-group-page
Bofan-Zhu Sep 8, 2025
eb91efe
add pageable to research group
Bofan-Zhu Sep 8, 2025
4e3e95e
resolve error
Bofan-Zhu Sep 8, 2025
57d369d
remove redundancy
Bofan-Zhu Sep 8, 2025
67135ca
adjust styling
Bofan-Zhu Sep 8, 2025
9d3a273
fix codacity
Bofan-Zhu Sep 8, 2025
b164378
add missing param tags according to javadoc
Bofan-Zhu Sep 8, 2025
4856440
fix editor validation
Bofan-Zhu Sep 8, 2025
560f4c3
fix input translation bug
Bofan-Zhu Sep 8, 2025
bb1840b
replace translation pipe
Bofan-Zhu Sep 9, 2025
d1386ce
Merge branch 'main' into 608-implement-research-group-page
Bofan-Zhu Sep 9, 2025
42416a5
shorten toast errors
Bofan-Zhu Sep 9, 2025
425681d
change description placeholder
Bofan-Zhu Sep 9, 2025
b10f05a
remove unused method
Bofan-Zhu Sep 10, 2025
a0d5a58
Merge branch 'main' into 608-implement-research-group-page
Bofan-Zhu Sep 10, 2025
e1631bb
resolve codacy
Bofan-Zhu Sep 10, 2025
bcf6e80
Merge branch '608-implement-research-group-page' of github.com:ls1int…
Bofan-Zhu Sep 10, 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
1,087 changes: 971 additions & 116 deletions openapi/openapi.yaml

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion src/main/java/de/tum/cit/aet/core/util/PageUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ public enum ColumnMapping {
/**
* Sortable columns used in job listings by professors.
*/
PROFESSOR_JOBS(Set.of("title", "state", "startDate", "createdAt", "lastModifiedAt"));
PROFESSOR_JOBS(Set.of("title", "state", "startDate", "createdAt", "lastModifiedAt")),

/**
* Sortable columns used in research group listings.
*/
RESEARCH_GROUPS(Set.of("head", "name", "abbreviation", "email", "website", "school", "description", "defaultFieldOfStudies", "street", "postalCode", "city"));

private final Set<String> sortableColumns;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package de.tum.cit.aet.usermanagement.dto;

import de.tum.cit.aet.core.exception.EntityNotFoundException;
import de.tum.cit.aet.usermanagement.domain.ResearchGroup;

import com.fasterxml.jackson.annotation.JsonInclude;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

/**
* DTO for {@link ResearchGroup}
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record ResearchGroupDTO(
Comment thread
Bofan-Zhu marked this conversation as resolved.
@NotBlank String name,
String abbreviation,
@NotBlank String head,
@Email String email,
String website,
String school,
String description,
String defaultFieldOfStudies,
String street,
String postalCode,
String city
) {

/**
* @param researchGroup the ResearchGroup entity
* @return the ResearchGroupDTO from the entity
* @throws EntityNotFoundException if the ResearchGroup entity is null
*/
public static ResearchGroupDTO getFromEntity(ResearchGroup researchGroup) {
if (researchGroup == null) {
throw new EntityNotFoundException("ResearchGroup entity should not be null");
}

return new ResearchGroupDTO(
researchGroup.getName(),
researchGroup.getAbbreviation(),
researchGroup.getHead(),
researchGroup.getEmail(),
researchGroup.getWebsite(),
researchGroup.getSchool(),
researchGroup.getDescription(),
researchGroup.getDefaultFieldOfStudies(),
researchGroup.getStreet(),
researchGroup.getPostalCode(),
researchGroup.getCity()
);
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
package de.tum.cit.aet.usermanagement.service;

import java.util.UUID;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import de.tum.cit.aet.core.dto.PageDTO;
import de.tum.cit.aet.core.dto.PageResponseDTO;
import de.tum.cit.aet.core.exception.EntityNotFoundException;
import de.tum.cit.aet.usermanagement.domain.ResearchGroup;
import de.tum.cit.aet.usermanagement.dto.ResearchGroupDTO;
import de.tum.cit.aet.usermanagement.dto.ResearchGroupLargeDTO;
import de.tum.cit.aet.usermanagement.repository.ResearchGroupRepository;
import java.util.UUID;
import lombok.RequiredArgsConstructor;

/**
* Service for managing research groups.
*/
@Service
Comment thread
Bofan-Zhu marked this conversation as resolved.
@RequiredArgsConstructor
Comment thread
ani-ib marked this conversation as resolved.
public class ResearchGroupService {

private final ResearchGroupRepository researchGroupRepository;

public ResearchGroupService(
ResearchGroupRepository researchGroupRepository) {
this.researchGroupRepository = researchGroupRepository;
/**
* Retrieves a research group by its ID.
*
* @param researchGroupId the ID of the research group
* @return the research group DTO
* @throws EntityNotFoundException if the research group is not found
*/
public ResearchGroupDTO getResearchGroup(UUID researchGroupId) {
ResearchGroup researchGroup = researchGroupRepository.findByIdElseThrow(researchGroupId);
return ResearchGroupDTO.getFromEntity(researchGroup);
}

/**
Expand All @@ -36,7 +56,50 @@ public ResearchGroupLargeDTO getResearchGroupDetails(UUID researchGroupId) {
researchGroup.getStreet(),
researchGroup.getPostalCode(),
researchGroup.getCity());
}

/**
* Retrieves all research groups.
*
* @param pageDTO the pagination parameters
* @return list of all research group DTOs
*/
public PageResponseDTO<ResearchGroupDTO> getAllResearchGroups(PageDTO pageDTO) {
Pageable pageable = PageRequest.of(pageDTO.pageNumber(), pageDTO.pageSize(), Sort.by(Sort.Direction.ASC, "name"));
Page<ResearchGroup> page = researchGroupRepository.findAll(pageable);
return new PageResponseDTO<>(page.get().map(ResearchGroupDTO::getFromEntity).toList(), page.getTotalElements());
}

/**
* Updates an existing research group.
*
* @param researchGroupId the ID of the research group to update
* @param researchGroupDTO the research group data to update
* @return the updated research group DTO
* @throws EntityNotFoundException if the research group is not found
*/
public ResearchGroupDTO updateResearchGroup(UUID researchGroupId, ResearchGroupDTO researchGroupDTO) {
ResearchGroup researchGroup = researchGroupRepository.findByIdElseThrow(researchGroupId);
updateEntityFromDTO(researchGroup, researchGroupDTO);

ResearchGroup updatedResearchGroup = researchGroupRepository.save(researchGroup);
return ResearchGroupDTO.getFromEntity(updatedResearchGroup);
}

/**
* Updates a ResearchGroup entity with values from the provided DTO.
*/
private void updateEntityFromDTO(ResearchGroup entity, ResearchGroupDTO dto) {
entity.setName(dto.name());
entity.setAbbreviation(dto.abbreviation());
entity.setHead(dto.head());
entity.setEmail(dto.email());
entity.setWebsite(dto.website());
entity.setSchool(dto.school());
entity.setDescription(dto.description());
entity.setStreet(dto.street());
entity.setPostalCode(dto.postalCode());
entity.setCity(dto.city());
entity.setDefaultFieldOfStudies(dto.defaultFieldOfStudies());
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,78 @@
package de.tum.cit.aet.usermanagement.web;

import de.tum.cit.aet.core.dto.PageDTO;
import de.tum.cit.aet.core.dto.PageResponseDTO;
import de.tum.cit.aet.core.security.CheckAccess;
import de.tum.cit.aet.usermanagement.dto.ResearchGroupDTO;
import de.tum.cit.aet.usermanagement.dto.ResearchGroupLargeDTO;
import de.tum.cit.aet.usermanagement.service.ResearchGroupService;
import java.util.UUID;
import lombok.RequiredArgsConstructor;

import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import de.tum.cit.aet.usermanagement.dto.ResearchGroupLargeDTO;
import de.tum.cit.aet.usermanagement.service.ResearchGroupService;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

/**
* REST controller for managing research groups.
*/
@RestController
@RequestMapping("/api/research-groups")
@RequiredArgsConstructor
public class ResearchGroupResource {

final ResearchGroupService researchGroupService;
private final ResearchGroupService researchGroupService;

public ResearchGroupResource(ResearchGroupService researchGroupService) {
this.researchGroupService = researchGroupService;
/**
* Get all research groups.
*
* @param pageDTO the pagination parameters
* @return the list of research groups
*/
@GetMapping
public ResponseEntity<PageResponseDTO<ResearchGroupDTO>> getAllResearchGroups(@ParameterObject @Valid @ModelAttribute PageDTO pageDTO) {
PageResponseDTO<ResearchGroupDTO> researchGroups = researchGroupService.getAllResearchGroups(pageDTO);
return ResponseEntity.ok(researchGroups);
}

/**
* Get a specific research group by ID.
*
* @param id the ID of the research group to retrieve
* @return the research group
*/
@GetMapping("/{id}")
public ResponseEntity<ResearchGroupDTO> getResearchGroup(@PathVariable UUID id) {
ResearchGroupDTO researchGroup = researchGroupService.getResearchGroup(id);
return ResponseEntity.ok(researchGroup);
}

/**
* Get detailed information about a research group.
*
* @param researchGroupId the ID of the research group to get details for
* @return the detailed research group information
*/
@GetMapping("/detail/{researchGroupId}")
public ResponseEntity<ResearchGroupLargeDTO> getResourceGroupDetails(@PathVariable UUID researchGroupId) {
return ResponseEntity.ok(researchGroupService.getResearchGroupDetails(researchGroupId));
}

/**
* Update a research group.
*
* @param id the ID of the research group to update
* @param researchGroupDTO the research group data to update
* @return the updated research group
*/
@PutMapping("/{id}")
@CheckAccess
public ResponseEntity<ResearchGroupDTO> updateResearchGroup(
@PathVariable UUID id,
Comment thread
Bofan-Zhu marked this conversation as resolved.
@Valid @RequestBody ResearchGroupDTO researchGroupDTO
) {
ResearchGroupDTO updatedResearchGroup = researchGroupService.updateResearchGroup(id, researchGroupDTO);
return ResponseEntity.ok(updatedResearchGroup);
}
}
8 changes: 8 additions & 0 deletions src/main/webapp/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ const routes: Routes = [
m => m.ResearchGroupTemplateEdit,
),
},
{
path: 'research-group/info',
canActivate: [UserRouteAccessService],
data: { authorities: [UserShortDTO.RolesEnum.Professor] },
loadComponent: () =>
import('./usermanagement/research-group/research-group-info/research-group-info.component').then(m => m.ResearchGroupInfoComponent),
title: 'researchGroup.groupInfoPage',
},

// ======================================================================================
// Error Handling
Expand Down
3 changes: 3 additions & 0 deletions src/main/webapp/app/generated/.openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
README.md
api.base.service.ts
api.module.ts
api/actuator.service.ts
api/api.ts
api/applicationEvaluationResource.service.ts
api/applicationResource.service.ts
Expand Down Expand Up @@ -52,6 +53,7 @@ model/jobDTO.ts
model/jobDetailDTO.ts
model/jobFilterOptionDTO.ts
model/jobFormDTO.ts
model/link.ts
model/loginRequestDTO.ts
model/models.ts
model/pageCreatedJobDTO.ts
Expand All @@ -63,6 +65,7 @@ model/ratingDTO.ts
model/ratingOverviewDTO.ts
model/rejectDTO.ts
model/researchGroup.ts
model/researchGroupDTO.ts
model/researchGroupLargeDTO.ts
model/researchGroupShortDTO.ts
model/sendCodeRequest.ts
Expand Down
Loading
Loading