Merge branch 'develop' into delete-forum-replies

This commit is contained in:
Andreas Svanberg 2025-03-17 13:41:29 +01:00
commit 7d82bb50b2
11 changed files with 182 additions and 9 deletions
core
pom.xml
src
main/java/se/su/dsv/scipro/match
test/java/se/su/dsv/scipro
pom.xml
test-data/src/main/java/se/su/dsv/scipro/testdata
view/src/main/java/se/su/dsv/scipro

@ -32,6 +32,10 @@
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>

@ -235,10 +235,8 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
if (authorParticipatingOnActiveIdea(coAuthor, ap)) {
return new Pair<>(Boolean.FALSE, PARTNER_ALREADY_PARTICIPATING_ERROR);
}
if (
coAuthor.getDegreeType() != ProjectType.UNKNOWN &&
coAuthor.getDegreeType() != idea.getProjectType().getDegreeType()
) {
List<ProjectType> typesForCoAuthor = applicationPeriodService.getTypesForStudent(ap, coAuthor);
if (!typesForCoAuthor.contains(idea.getProjectType())) {
return new Pair<>(Boolean.FALSE, WRONG_LEVEL_FOR_YOUR_PARTNER);
}
if (!projectService.getActiveProjectsByUserAndProjectType(coAuthor, idea.getProjectType()).isEmpty()) {

@ -241,6 +241,7 @@ public class IdeaServiceImplTest {
when(generalSystemSettingsService.getGeneralSystemSettingsInstance()).thenReturn(new GeneralSystemSettings());
Idea idea = createBachelorIdea(Idea.Status.UNMATCHED);
when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(bachelor));
when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
Pair<Boolean, String> acceptance = ideaService.validateStudentAcceptance(
idea,
@ -401,6 +402,39 @@ public class IdeaServiceImplTest {
assertEquals(expected, ideaService.countAuthorsByApplicationPeriod(applicationPeriod, params));
}
@Test
public void wrong_type_for_author() {
when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(master));
when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
assertPair(
false,
"The idea is the wrong level for you, please pick another one.",
ideaService.validateStudentAcceptance(
createBachelorIdea(Idea.Status.UNMATCHED),
student,
coAuthor,
applicationPeriod
)
);
}
@Test
public void wrong_type_for_partner() {
when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(master));
assertPair(
false,
"The idea is the wrong level for your partner, please pick another one.",
ideaService.validateStudentAcceptance(
createBachelorIdea(Idea.Status.UNMATCHED),
student,
coAuthor,
applicationPeriod
)
);
}
private Idea mockInactiveIdea() {
Idea idea = new Idea();
Match match = new Match();

@ -6,7 +6,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.common.eventbus.EventBus;
import com.sun.net.httpserver.HttpServer;
import jakarta.inject.Inject;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
@ -15,6 +19,9 @@ import org.junit.jupiter.api.Test;
import se.su.dsv.scipro.finalseminar.FinalSeminar;
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
import se.su.dsv.scipro.finalseminar.OppositionApprovedEvent;
import se.su.dsv.scipro.grading.GetGradeError;
import se.su.dsv.scipro.grading.GradingServiceImpl;
import se.su.dsv.scipro.grading.Result;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.system.DegreeType;
@ -149,6 +156,44 @@ public class GradingReportServiceImplIntegrationTest extends IntegrationTest {
assertNull(oppositionCriterion.getFeedback());
}
@Test
public void test_json_deserialization() throws IOException {
String json =
"""
{
"grade": "A",
"reported": "2021-01-01"
}
""";
HttpServer httpServer = startHttpServerWithJsonResponse(json);
int port = httpServer.getAddress().getPort();
GradingServiceImpl gradingService = new GradingServiceImpl("http://localhost:" + port);
Either<GetGradeError, Optional<Result>> result = gradingService.getResult("token", 1, 2, 3);
Optional<Result> right = result.right();
assertTrue(right.isPresent());
assertEquals(LocalDate.of(2021, 1, 1), right.get().reported());
httpServer.stop(0);
}
private static HttpServer startHttpServerWithJsonResponse(String json) throws IOException {
HttpServer httpServer = HttpServer.create();
httpServer.createContext("/", exchange -> {
try (exchange) {
byte[] response = json.getBytes(StandardCharsets.UTF_8);
exchange.getResponseHeaders().add("Content-Type", "application/json");
exchange.sendResponseHeaders(200, response.length);
exchange.getResponseBody().write(response);
}
});
httpServer.bind(new InetSocketAddress("localhost", 0), 0);
httpServer.start();
return httpServer;
}
private void addOppositionCriterion() {
gradingReportTemplate = createOppositionCriteria(gradingReportTemplate, 2);
gradingReport = createGradingReport(project, student);

@ -26,7 +26,7 @@
<wicket.version>10.4.0</wicket.version>
<jakarta.persistence-api.version>3.1.0</jakarta.persistence-api.version>
<querydsl.version>5.0.0</querydsl.version>
<poi.version>5.2.5</poi.version>
<poi.version>5.4.0</poi.version>
<!--
When updating spring-boot check if the transitive dependency on json-smart has been

@ -1,6 +1,9 @@
package se.su.dsv.scipro.testdata;
import java.util.List;
import se.su.dsv.scipro.match.Keyword;
import se.su.dsv.scipro.system.ProjectType;
import se.su.dsv.scipro.system.ResearchArea;
/// All the base test data that can be re-used in different test cases.
///
@ -16,4 +19,11 @@ public interface BaseData {
ProjectType bachelor();
ProjectType magister();
ProjectType master();
/**
* @return generic research area with some keywords attached to it
*/
ResearchAreaAndKeywords researchArea();
record ResearchAreaAndKeywords(ResearchArea researchArea, List<Keyword> keywords) {}
}

@ -2193,6 +2193,11 @@ public class DataInitializer implements Lifecycle, BaseData, Factory {
return createEmployee(firstName);
}
@Override
public ResearchAreaAndKeywords researchArea() {
return new ResearchAreaAndKeywords(researchArea1, List.of(keyword1, keyword2));
}
private static final class SimpleTextFile implements FileUpload {
private final User uploader;

@ -0,0 +1,68 @@
package se.su.dsv.scipro.testdata.populators;
import jakarta.inject.Inject;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;
import org.springframework.stereotype.Service;
import se.su.dsv.scipro.match.ApplicationPeriod;
import se.su.dsv.scipro.match.ApplicationPeriodService;
import se.su.dsv.scipro.match.Idea;
import se.su.dsv.scipro.match.IdeaService;
import se.su.dsv.scipro.match.Target;
import se.su.dsv.scipro.match.TargetService;
import se.su.dsv.scipro.system.User;
import se.su.dsv.scipro.testdata.BaseData;
import se.su.dsv.scipro.testdata.Factory;
import se.su.dsv.scipro.testdata.TestDataPopulator;
@Service
public class PartnerTypeExemption implements TestDataPopulator {
private final ApplicationPeriodService applicationPeriodService;
private final IdeaService ideaService;
private final TargetService targetService;
@Inject
public PartnerTypeExemption(
ApplicationPeriodService applicationPeriodService,
IdeaService ideaService,
TargetService targetService
) {
this.applicationPeriodService = applicationPeriodService;
this.ideaService = ideaService;
this.targetService = targetService;
}
@Override
public void populate(BaseData baseData, Factory factory) {
factory.createAuthor("Oskar");
User johan = factory.createAuthor("Johan");
johan.setDegreeType(baseData.master().getDegreeType());
User supervisor = factory.createSupervisor("Elsa");
ApplicationPeriod applicationPeriod = new ApplicationPeriod("Supervisor ideas");
applicationPeriod.setStartDate(LocalDate.now());
applicationPeriod.setEndDate(LocalDate.now().plusDays(14));
applicationPeriod.setCourseStartDateTime(LocalDateTime.now().plusDays(15));
applicationPeriod.setProjectTypes(Set.of(baseData.bachelor()));
applicationPeriodService.save(applicationPeriod);
Target target = targetService.findOne(applicationPeriod, supervisor, baseData.bachelor());
target.setTarget(10);
targetService.save(target);
Idea idea = new Idea();
idea.setPublished(true);
idea.setTitle("The next gen AI 2.0 turbo edition");
idea.setPrerequisites("Hacker experience");
idea.setDescription("Better than all the rest");
idea.setProjectType(baseData.bachelor());
idea.setApplicationPeriod(applicationPeriod);
idea.setResearchArea(baseData.researchArea().researchArea());
ideaService.saveSupervisorIdea(idea, supervisor, baseData.researchArea().keywords(), true);
}
}

@ -1,6 +1,5 @@
package se.su.dsv.scipro.datatables.project;
import com.google.common.eventbus.EventBus;
import jakarta.inject.Inject;
import java.util.*;
import org.apache.wicket.ajax.AjaxRequestTarget;
@ -33,7 +32,6 @@ import se.su.dsv.scipro.components.datatables.MultipleUsersColumn;
import se.su.dsv.scipro.components.datatables.UserColumn;
import se.su.dsv.scipro.dataproviders.FilteredDataProvider;
import se.su.dsv.scipro.datatables.AjaxCheckboxWrapper;
import se.su.dsv.scipro.notifications.NotificationController;
import se.su.dsv.scipro.profile.UserLinkPanel;
import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.project.ProjectService;
@ -45,7 +43,6 @@ import se.su.dsv.scipro.system.ProjectType;
import se.su.dsv.scipro.system.ProjectTypeService;
import se.su.dsv.scipro.system.ResearchArea;
import se.su.dsv.scipro.system.User;
import se.su.dsv.scipro.system.UserService;
import se.su.dsv.scipro.util.PageParameterKeys;
public class ProjectDataPanel extends Panel {
@ -170,6 +167,11 @@ public class ProjectDataPanel extends Panel {
) {
cellItem.add(new ReviewerColumnCell(componentId, rowModel));
}
@Override
public IModel<?> getDataModel(IModel<Project> rowModel) {
return rowModel.map(Project::getReviewer).map(User::getFullName);
}
};
}

@ -59,6 +59,11 @@ public class EditGroupPanel extends Panel {
});
add(
new ListView<>("available_projects", availableProjects) {
{
// must re-use list items to maintain form component (checkboxes) state
setReuseItems(true);
}
@Override
protected void populateItem(ListItem<Project> item) {
CheckBox checkbox = new CheckBox("selected", new SelectProjectModel(model, item.getModel()));

@ -72,7 +72,9 @@ public class ExcelExporter extends AbstractDataExporter {
for (int i = 0; i < columns.size(); i++) {
Object cellValue = columns.get(i).getDataModel(data).getObject();
Cell cell = row.createCell(i);
cell.setCellValue(String.valueOf(cellValue));
if (cellValue != null) {
cell.setCellValue(cellValue.toString());
}
}
}
}