Compare commits
13 Commits
b821c16e48
...
819d5c7935
Author | SHA1 | Date | |
---|---|---|---|
819d5c7935 | |||
6c91df6797 | |||
e4711971cc | |||
075c691ba3 | |||
6834ebaac1 | |||
2ac30fa980 | |||
7504c267c5 | |||
6b77142a06 | |||
59e3ec3fd9 | |||
9ede262e7b | |||
de18f200a7 | |||
23e0a7f5ea | |||
ed365bd7f5 |
Dockerfilecheckstyle.xml
core
pom.xml
pom.xmlsrc
main
java/se/su/dsv/scipro
forum
BasicForumService.javaBasicForumServiceImpl.javaProjectForumService.javaProjectForumServiceImpl.java
match
xsd
test/java/se/su/dsv/scipro
test-data/src/main/java/se/su/dsv/scipro/testdata
view/src/main/java/se/su/dsv/scipro
datatables/project
forum
group
io
@ -24,6 +24,7 @@ COPY test-data/src/ test-data/src/
|
||||
RUN ./mvnw package \
|
||||
--define skipTests \
|
||||
--activate-profiles branch,DEV \
|
||||
--define checkstyle.skip=true \
|
||||
--define skip.npm \
|
||||
--define skip.installnodenpm
|
||||
|
||||
|
7
checkstyle.xml
Normal file
7
checkstyle.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
</module>
|
@ -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>
|
||||
|
@ -32,5 +32,10 @@ public interface BasicForumService extends Serializable {
|
||||
|
||||
boolean canDelete(ForumPost forumPost);
|
||||
|
||||
void deletePost(ForumPost post);
|
||||
Deletion deletePost(ForumPost post);
|
||||
|
||||
enum Deletion {
|
||||
SINGLE_POST,
|
||||
ENTIRE_THREAD,
|
||||
}
|
||||
}
|
||||
|
@ -185,15 +185,17 @@ public class BasicForumServiceImpl implements BasicForumService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deletePost(ForumPost post) {
|
||||
public Deletion deletePost(ForumPost post) {
|
||||
if (!canDelete(post)) {
|
||||
throw new PostCantBeDeletedException();
|
||||
}
|
||||
if (isInitialPost(post)) {
|
||||
threadRepository.delete(post.getForumThread());
|
||||
return Deletion.ENTIRE_THREAD;
|
||||
} else {
|
||||
post.setDeleted(true);
|
||||
postRepository.save(post);
|
||||
return Deletion.SINGLE_POST;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,4 +24,8 @@ public interface ProjectForumService {
|
||||
List<Pair<ProjectThread, ForumPost>> latestPost(Project a, int amount);
|
||||
|
||||
long getUnreadThreadsCount(Project project, User user);
|
||||
|
||||
boolean canDelete(ProjectThread projectThread, ForumPost forumPost);
|
||||
|
||||
void deletePost(ProjectThread projectThread, ForumPost forumPost);
|
||||
}
|
||||
|
@ -121,6 +121,20 @@ public class ProjectForumServiceImpl implements ProjectForumService {
|
||||
return basicForumService.countUnreadThreads(list, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDelete(ProjectThread projectThread, ForumPost forumPost) {
|
||||
return basicForumService.canDelete(forumPost);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deletePost(ProjectThread projectThread, ForumPost forumPost) {
|
||||
BasicForumService.Deletion deletion = basicForumService.deletePost(forumPost);
|
||||
if (deletion == BasicForumService.Deletion.ENTIRE_THREAD) {
|
||||
projectThreadRepository.delete(projectThread);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectThread findOne(long threadId) {
|
||||
return projectThreadRepository.findOne(threadId);
|
||||
|
@ -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()) {
|
||||
|
@ -559,7 +559,7 @@
|
||||
|
||||
<xs:complexType name="course">
|
||||
<xs:sequence>
|
||||
<xs:element name="courseCode" type="xs:string" minOccurs="0">
|
||||
<xs:element name="courseCode" type="xs:string" minOccurs="1">
|
||||
</xs:element>
|
||||
<xs:element name="credits" type="xs:float" minOccurs="1">
|
||||
</xs:element>
|
||||
@ -567,6 +567,8 @@
|
||||
</xs:element>
|
||||
<xs:element name="level" type="educationalLevel" minOccurs="0">
|
||||
</xs:element>
|
||||
<xs:element name="degreeThesisCourse" type="xs:boolean" minOccurs="1">
|
||||
</xs:element>
|
||||
<xs:element name="eduInstDesignation" type="xs:string" minOccurs="1">
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
@ -5,6 +5,7 @@ import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@ -57,7 +58,10 @@ public class BasicForumServiceIntegrationTest extends IntegrationTest {
|
||||
setLoggedInAs(commenter);
|
||||
|
||||
assertTrue(basicForumService.canDelete(reply));
|
||||
assertDoesNotThrow(() -> basicForumService.deletePost(reply));
|
||||
assertDoesNotThrow(() -> {
|
||||
BasicForumService.Deletion deletion = basicForumService.deletePost(reply);
|
||||
assertEquals(BasicForumService.Deletion.SINGLE_POST, deletion);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -204,7 +208,8 @@ public class BasicForumServiceIntegrationTest extends IntegrationTest {
|
||||
|
||||
setLoggedInAs(op);
|
||||
|
||||
basicForumService.deletePost(post);
|
||||
BasicForumService.Deletion deletion = basicForumService.deletePost(post);
|
||||
assertEquals(BasicForumService.Deletion.ENTIRE_THREAD, deletion);
|
||||
|
||||
ForumThread threadById = basicForumService.findThreadById(thread.getId());
|
||||
assertNull(threadById, "Thread was not deleted");
|
||||
|
@ -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);
|
||||
|
24
pom.xml
24
pom.xml
@ -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
|
||||
@ -211,6 +211,11 @@
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
@ -312,6 +317,23 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<configLocation>checkstyle.xml</configLocation>
|
||||
<failOnViolation>true</failOnViolation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>validate</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -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;
|
||||
|
68
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
vendored
Normal file
68
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
vendored
Normal file
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,4 +10,10 @@ public interface ForumThread<A> extends IClusterable {
|
||||
ForumPost reply(A a, User poster, String content, Set<Attachment> attachments);
|
||||
String getSubject(A a);
|
||||
void setRead(User user, A a);
|
||||
|
||||
default boolean canDelete(A a, ForumPost forumPost) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void deletePost(A a, ForumPost forumPost) {}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package se.su.dsv.scipro.forum.panels.threaded;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.link.Link;
|
||||
@ -13,11 +12,9 @@ import se.su.dsv.scipro.components.ListAdapterModel;
|
||||
import se.su.dsv.scipro.components.SmarterLinkMultiLineLabel;
|
||||
import se.su.dsv.scipro.data.enums.DateStyle;
|
||||
import se.su.dsv.scipro.file.FileReference;
|
||||
import se.su.dsv.scipro.forum.BasicForumService;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||
import se.su.dsv.scipro.profile.UserLinkPanel;
|
||||
import se.su.dsv.scipro.repository.panels.ViewAttachmentPanel;
|
||||
import se.su.dsv.scipro.session.SciProSession;
|
||||
|
||||
public class ForumPostPanel extends Panel {
|
||||
|
||||
@ -26,9 +23,6 @@ public class ForumPostPanel extends Panel {
|
||||
public static final String CONTENT = "content";
|
||||
public static final String ATTACHMENT = "attachment";
|
||||
|
||||
@Inject
|
||||
private BasicForumService basicForumService;
|
||||
|
||||
public ForumPostPanel(String id, final IModel<ForumPost> model) {
|
||||
super(id);
|
||||
add(new UserLinkPanel(POSTED_BY, LambdaModel.of(model, ForumPost::getPostedBy, ForumPost::setPostedBy)));
|
||||
@ -75,22 +69,23 @@ public class ForumPostPanel extends Panel {
|
||||
@Override
|
||||
public void onClick() {
|
||||
ForumPost post = getModelObject();
|
||||
basicForumService.deletePost(post);
|
||||
onPostDeleted();
|
||||
deletePost(post).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(allowDeletion() && basicForumService.canDelete(getModelObject()));
|
||||
setVisible(deletePost(getModelObject()) != null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected boolean allowDeletion() {
|
||||
return false;
|
||||
/**
|
||||
* @param forumPost the post to delete
|
||||
* @return a runnable that deletes the post, or {@code null} if it can not be deleted
|
||||
*/
|
||||
protected Runnable deletePost(ForumPost forumPost) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostDeleted() {}
|
||||
}
|
||||
|
@ -40,4 +40,14 @@ public class ProjectForumThread implements ForumThread<ProjectThread> {
|
||||
public void setRead(User user, ProjectThread thread) {
|
||||
projectForumService.markRead(user, thread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDelete(ProjectThread projectThread, ForumPost forumPost) {
|
||||
return projectForumService.canDelete(projectThread, forumPost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePost(ProjectThread projectThread, ForumPost forumPost) {
|
||||
projectForumService.deletePost(projectThread, forumPost);
|
||||
}
|
||||
}
|
||||
|
@ -62,14 +62,16 @@ public class ViewForumThreadPanel<A> extends GenericPanel<A> {
|
||||
item.add(
|
||||
new ForumPostPanel(POST, item.getModel()) {
|
||||
@Override
|
||||
protected boolean allowDeletion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostDeleted() {
|
||||
// Refresh the list of posts
|
||||
listView.detach();
|
||||
protected Runnable deletePost(ForumPost forumPost) {
|
||||
if (forumThread.canDelete(ViewForumThreadPanel.this.getModelObject(), forumPost)) {
|
||||
return () -> {
|
||||
forumThread.deletePost(ViewForumThreadPanel.this.getModelObject(), forumPost);
|
||||
// Refresh the list of posts
|
||||
listView.detach();
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user