Merge branch 'develop' into checkstyle
This commit is contained in:
commit
db1fcea161
core
test-data/src/main/java/se/su/dsv/scipro/testdata
view/src
main/java/se/su/dsv/scipro
forum/panels/threaded
group
test/java/se/su/dsv/scipro/forum/panels/threaded
@ -32,6 +32,10 @@
|
|||||||
<groupId>org.glassfish.jersey.media</groupId>
|
<groupId>org.glassfish.jersey.media</groupId>
|
||||||
<artifactId>jersey-media-json-jackson</artifactId>
|
<artifactId>jersey-media-json-jackson</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jersey.inject</groupId>
|
||||||
|
<artifactId>jersey-hk2</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context</artifactId>
|
<artifactId>spring-context</artifactId>
|
||||||
|
@ -349,14 +349,16 @@ public class CoreConfig {
|
|||||||
ForumPostReadStateRepository readStateRepository,
|
ForumPostReadStateRepository readStateRepository,
|
||||||
AbstractThreadRepository threadRepository,
|
AbstractThreadRepository threadRepository,
|
||||||
FileService fileService,
|
FileService fileService,
|
||||||
EventBus eventBus
|
EventBus eventBus,
|
||||||
|
CurrentUser currentUser
|
||||||
) {
|
) {
|
||||||
return new BasicForumServiceImpl(
|
return new BasicForumServiceImpl(
|
||||||
forumPostRepository,
|
forumPostRepository,
|
||||||
readStateRepository,
|
readStateRepository,
|
||||||
threadRepository,
|
threadRepository,
|
||||||
fileService,
|
fileService,
|
||||||
eventBus
|
eventBus,
|
||||||
|
currentUser
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,4 +23,12 @@ public interface BasicForumService extends Serializable {
|
|||||||
ForumThread createThread(String subject);
|
ForumThread createThread(String subject);
|
||||||
|
|
||||||
long countUnreadThreads(List<ForumThread> forumThreadList, User user);
|
long countUnreadThreads(List<ForumThread> forumThreadList, User user);
|
||||||
|
|
||||||
|
ForumPost getLastPost(ForumThread forumThread);
|
||||||
|
|
||||||
|
boolean hasAttachments(ForumThread forumThread);
|
||||||
|
|
||||||
|
boolean canDelete(ForumPost forumPost);
|
||||||
|
|
||||||
|
void deletePost(ForumPost post);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import se.su.dsv.scipro.file.FileService;
|
|||||||
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||||
import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState;
|
import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState;
|
||||||
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
||||||
|
import se.su.dsv.scipro.system.CurrentUser;
|
||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
public class BasicForumServiceImpl implements BasicForumService {
|
public class BasicForumServiceImpl implements BasicForumService {
|
||||||
@ -19,6 +20,7 @@ public class BasicForumServiceImpl implements BasicForumService {
|
|||||||
private final ForumPostReadStateRepository readStateRepository;
|
private final ForumPostReadStateRepository readStateRepository;
|
||||||
private final FileService fileService;
|
private final FileService fileService;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final CurrentUser currentUserProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BasicForumServiceImpl(
|
public BasicForumServiceImpl(
|
||||||
@ -26,13 +28,15 @@ public class BasicForumServiceImpl implements BasicForumService {
|
|||||||
final ForumPostReadStateRepository readStateRepository,
|
final ForumPostReadStateRepository readStateRepository,
|
||||||
AbstractThreadRepository threadRepository,
|
AbstractThreadRepository threadRepository,
|
||||||
final FileService fileService,
|
final FileService fileService,
|
||||||
final EventBus eventBus
|
final EventBus eventBus,
|
||||||
|
final CurrentUser currentUserProvider
|
||||||
) {
|
) {
|
||||||
this.postRepository = postRepository;
|
this.postRepository = postRepository;
|
||||||
this.readStateRepository = readStateRepository;
|
this.readStateRepository = readStateRepository;
|
||||||
this.threadRepository = threadRepository;
|
this.threadRepository = threadRepository;
|
||||||
this.fileService = fileService;
|
this.fileService = fileService;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.currentUserProvider = currentUserProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,7 +70,7 @@ public class BasicForumServiceImpl implements BasicForumService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isThreadRead(User user, ForumThread forumThread) {
|
public boolean isThreadRead(User user, ForumThread forumThread) {
|
||||||
for (ForumPost post : forumThread.getPosts()) {
|
for (ForumPost post : getPosts(forumThread)) {
|
||||||
if (!getReadState(user, post).isRead()) {
|
if (!getReadState(user, post).isRead()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -133,4 +137,56 @@ public class BasicForumServiceImpl implements BasicForumService {
|
|||||||
|
|
||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForumPost getLastPost(ForumThread forumThread) {
|
||||||
|
return Collections.max(
|
||||||
|
getPosts(forumThread),
|
||||||
|
Comparator.comparing(ForumPost::getDateCreated).thenComparing(ForumPost::getId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAttachments(ForumThread forumThread) {
|
||||||
|
for (ForumPost post : getPosts(forumThread)) {
|
||||||
|
if (!post.getAttachments().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDelete(ForumPost forumPost) {
|
||||||
|
ForumPost initialPost = forumPost.getForumThread().getPosts().get(0);
|
||||||
|
if (forumPost.equals(initialPost)) {
|
||||||
|
// The initial post in a thread can never be deleted
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = currentUserProvider.get();
|
||||||
|
// Current user can be null meaning the call came from the system
|
||||||
|
if (user == null) {
|
||||||
|
// Allow the system to delete any post
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return Objects.equals(forumPost.getPostedBy(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void deletePost(ForumPost post) {
|
||||||
|
if (!canDelete(post)) {
|
||||||
|
throw new PostCantBeDeletedException();
|
||||||
|
}
|
||||||
|
post.setDeleted(true);
|
||||||
|
postRepository.save(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class PostCantBeDeletedException extends IllegalArgumentException {
|
||||||
|
|
||||||
|
public PostCantBeDeletedException() {
|
||||||
|
super("User is not allowed to delete post");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,13 +116,4 @@ public class ForumThread extends LazyDeletableDomainObject {
|
|||||||
public User getCreatedBy() {
|
public User getCreatedBy() {
|
||||||
return getPosts().get(0).getPostedBy();
|
return getPosts().get(0).getPostedBy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAttachments() {
|
|
||||||
for (ForumPost post : posts) {
|
|
||||||
if (!post.getAttachments().isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -235,10 +235,8 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
|
|||||||
if (authorParticipatingOnActiveIdea(coAuthor, ap)) {
|
if (authorParticipatingOnActiveIdea(coAuthor, ap)) {
|
||||||
return new Pair<>(Boolean.FALSE, PARTNER_ALREADY_PARTICIPATING_ERROR);
|
return new Pair<>(Boolean.FALSE, PARTNER_ALREADY_PARTICIPATING_ERROR);
|
||||||
}
|
}
|
||||||
if (
|
List<ProjectType> typesForCoAuthor = applicationPeriodService.getTypesForStudent(ap, coAuthor);
|
||||||
coAuthor.getDegreeType() != ProjectType.UNKNOWN &&
|
if (!typesForCoAuthor.contains(idea.getProjectType())) {
|
||||||
coAuthor.getDegreeType() != idea.getProjectType().getDegreeType()
|
|
||||||
) {
|
|
||||||
return new Pair<>(Boolean.FALSE, WRONG_LEVEL_FOR_YOUR_PARTNER);
|
return new Pair<>(Boolean.FALSE, WRONG_LEVEL_FOR_YOUR_PARTNER);
|
||||||
}
|
}
|
||||||
if (!projectService.getActiveProjectsByUserAndProjectType(coAuthor, idea.getProjectType()).isEmpty()) {
|
if (!projectService.getActiveProjectsByUserAndProjectType(coAuthor, idea.getProjectType()).isEmpty()) {
|
||||||
|
@ -559,7 +559,7 @@
|
|||||||
|
|
||||||
<xs:complexType name="course">
|
<xs:complexType name="course">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="courseCode" type="xs:string" minOccurs="0">
|
<xs:element name="courseCode" type="xs:string" minOccurs="1">
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="credits" type="xs:float" minOccurs="1">
|
<xs:element name="credits" type="xs:float" minOccurs="1">
|
||||||
</xs:element>
|
</xs:element>
|
||||||
@ -567,6 +567,8 @@
|
|||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="level" type="educationalLevel" minOccurs="0">
|
<xs:element name="level" type="educationalLevel" minOccurs="0">
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
<xs:element name="degreeThesisCourse" type="xs:boolean" minOccurs="1">
|
||||||
|
</xs:element>
|
||||||
<xs:element name="eduInstDesignation" type="xs:string" minOccurs="1">
|
<xs:element name="eduInstDesignation" type="xs:string" minOccurs="1">
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
|
@ -121,6 +121,8 @@ public class BasicForumServiceImplTest {
|
|||||||
ForumThread forumThread = new ForumThread();
|
ForumThread forumThread = new ForumThread();
|
||||||
forumThread.addPost(post);
|
forumThread.addPost(post);
|
||||||
|
|
||||||
|
when(postRepository.findByThread(forumThread)).thenReturn(List.of(post));
|
||||||
|
|
||||||
when(readStateRepository.find(eq(goodUser), isA(ForumPost.class))).thenReturn(readState);
|
when(readStateRepository.find(eq(goodUser), isA(ForumPost.class))).thenReturn(readState);
|
||||||
when(readStateRepository.find(eq(badUser), isA(ForumPost.class))).thenReturn(notReadState);
|
when(readStateRepository.find(eq(badUser), isA(ForumPost.class))).thenReturn(notReadState);
|
||||||
|
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
package se.su.dsv.scipro.forum;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||||
|
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
import se.su.dsv.scipro.test.IntegrationTest;
|
||||||
|
|
||||||
|
public class BasicForumServiceIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BasicForumService basicForumService;
|
||||||
|
|
||||||
|
private User op;
|
||||||
|
private User commenter;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
User op = User.builder().firstName("Bill").lastName("Gates").emailAddress("bill@example.com").build();
|
||||||
|
this.op = save(op);
|
||||||
|
|
||||||
|
User commenter = User.builder().firstName("Steve").lastName("Jobs").emailAddress("steve@example.com").build();
|
||||||
|
this.commenter = save(commenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_not_delete_original_post() {
|
||||||
|
ForumThread thread = basicForumService.createThread("Test thread");
|
||||||
|
ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
|
||||||
|
|
||||||
|
setLoggedInAs(op);
|
||||||
|
|
||||||
|
assertFalse(basicForumService.canDelete(originalPost));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> basicForumService.deletePost(originalPost));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_delete_reply_to_original_post() {
|
||||||
|
ForumThread thread = basicForumService.createThread("Test thread");
|
||||||
|
ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
|
||||||
|
ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
|
||||||
|
|
||||||
|
setLoggedInAs(commenter);
|
||||||
|
|
||||||
|
assertTrue(basicForumService.canDelete(reply));
|
||||||
|
assertDoesNotThrow(() -> basicForumService.deletePost(reply));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void can_not_delete_someone_elses_reply() {
|
||||||
|
ForumThread thread = basicForumService.createThread("Test thread");
|
||||||
|
ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
|
||||||
|
ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
|
||||||
|
|
||||||
|
setLoggedInAs(op);
|
||||||
|
|
||||||
|
assertFalse(basicForumService.canDelete(reply));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> basicForumService.deletePost(reply));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void system_can_delete_all_replies() {
|
||||||
|
ForumThread thread = basicForumService.createThread("Test thread");
|
||||||
|
ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
|
||||||
|
ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
|
||||||
|
ForumPost secondReply = basicForumService.createReply(thread, op, "Test post", Set.of());
|
||||||
|
|
||||||
|
setLoggedInAs(null);
|
||||||
|
|
||||||
|
assertTrue(basicForumService.canDelete(reply));
|
||||||
|
assertDoesNotThrow(() -> basicForumService.deletePost(reply));
|
||||||
|
assertTrue(basicForumService.canDelete(secondReply));
|
||||||
|
assertDoesNotThrow(() -> basicForumService.deletePost(secondReply));
|
||||||
|
}
|
||||||
|
}
|
@ -241,6 +241,7 @@ public class IdeaServiceImplTest {
|
|||||||
when(generalSystemSettingsService.getGeneralSystemSettingsInstance()).thenReturn(new GeneralSystemSettings());
|
when(generalSystemSettingsService.getGeneralSystemSettingsInstance()).thenReturn(new GeneralSystemSettings());
|
||||||
Idea idea = createBachelorIdea(Idea.Status.UNMATCHED);
|
Idea idea = createBachelorIdea(Idea.Status.UNMATCHED);
|
||||||
when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(bachelor));
|
when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(bachelor));
|
||||||
|
when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
|
||||||
|
|
||||||
Pair<Boolean, String> acceptance = ideaService.validateStudentAcceptance(
|
Pair<Boolean, String> acceptance = ideaService.validateStudentAcceptance(
|
||||||
idea,
|
idea,
|
||||||
@ -401,6 +402,39 @@ public class IdeaServiceImplTest {
|
|||||||
assertEquals(expected, ideaService.countAuthorsByApplicationPeriod(applicationPeriod, params));
|
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() {
|
private Idea mockInactiveIdea() {
|
||||||
Idea idea = new Idea();
|
Idea idea = new Idea();
|
||||||
Match match = new Match();
|
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 static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.sun.net.httpserver.HttpServer;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.Month;
|
import java.time.Month;
|
||||||
import java.util.*;
|
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.FinalSeminar;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||||
import se.su.dsv.scipro.finalseminar.OppositionApprovedEvent;
|
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.project.Project;
|
||||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||||
import se.su.dsv.scipro.system.DegreeType;
|
import se.su.dsv.scipro.system.DegreeType;
|
||||||
@ -149,6 +156,44 @@ public class GradingReportServiceImplIntegrationTest extends IntegrationTest {
|
|||||||
assertNull(oppositionCriterion.getFeedback());
|
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() {
|
private void addOppositionCriterion() {
|
||||||
gradingReportTemplate = createOppositionCriteria(gradingReportTemplate, 2);
|
gradingReportTemplate = createOppositionCriteria(gradingReportTemplate, 2);
|
||||||
gradingReport = createGradingReport(project, student);
|
gradingReport = createGradingReport(project, student);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package se.su.dsv.scipro.test;
|
package se.su.dsv.scipro.test;
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
import jakarta.persistence.EntityTransaction;
|
import jakarta.persistence.EntityTransaction;
|
||||||
@ -28,6 +29,7 @@ import se.su.dsv.scipro.RepositoryConfiguration;
|
|||||||
import se.su.dsv.scipro.profiles.CurrentProfile;
|
import se.su.dsv.scipro.profiles.CurrentProfile;
|
||||||
import se.su.dsv.scipro.sukat.Sukat;
|
import se.su.dsv.scipro.sukat.Sukat;
|
||||||
import se.su.dsv.scipro.system.CurrentUser;
|
import se.su.dsv.scipro.system.CurrentUser;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
@Testcontainers
|
@Testcontainers
|
||||||
public abstract class SpringTest {
|
public abstract class SpringTest {
|
||||||
@ -38,6 +40,9 @@ public abstract class SpringTest {
|
|||||||
@Container
|
@Container
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TestUser testUser;
|
||||||
|
|
||||||
private CapturingEventBus capturingEventBus;
|
private CapturingEventBus capturingEventBus;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@ -64,6 +69,8 @@ public abstract class SpringTest {
|
|||||||
annotationConfigApplicationContext.getBeanFactory().registerSingleton("entityManager", this.entityManager);
|
annotationConfigApplicationContext.getBeanFactory().registerSingleton("entityManager", this.entityManager);
|
||||||
annotationConfigApplicationContext.refresh();
|
annotationConfigApplicationContext.refresh();
|
||||||
annotationConfigApplicationContext.getAutowireCapableBeanFactory().autowireBean(this);
|
annotationConfigApplicationContext.getAutowireCapableBeanFactory().autowireBean(this);
|
||||||
|
|
||||||
|
testUser.setUser(null); // default to system
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@ -83,6 +90,10 @@ public abstract class SpringTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setLoggedInAs(User user) {
|
||||||
|
this.testUser.setUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<Object> getPublishedEvents() {
|
protected List<Object> getPublishedEvents() {
|
||||||
return capturingEventBus.publishedEvents;
|
return capturingEventBus.publishedEvents;
|
||||||
}
|
}
|
||||||
@ -108,7 +119,7 @@ public abstract class SpringTest {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CurrentUser currentUser() {
|
public CurrentUser currentUser() {
|
||||||
return () -> null;
|
return new TestUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -129,4 +140,18 @@ public abstract class SpringTest {
|
|||||||
super.post(event);
|
super.post(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TestUser implements CurrentUser {
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User get() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package se.su.dsv.scipro.testdata;
|
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.ProjectType;
|
||||||
|
import se.su.dsv.scipro.system.ResearchArea;
|
||||||
|
|
||||||
/// All the base test data that can be re-used in different test cases.
|
/// All the base test data that can be re-used in different test cases.
|
||||||
///
|
///
|
||||||
@ -16,4 +19,11 @@ public interface BaseData {
|
|||||||
ProjectType bachelor();
|
ProjectType bachelor();
|
||||||
ProjectType magister();
|
ProjectType magister();
|
||||||
ProjectType master();
|
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);
|
return createEmployee(firstName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResearchAreaAndKeywords researchArea() {
|
||||||
|
return new ResearchAreaAndKeywords(researchArea1, List.of(keyword1, keyword2));
|
||||||
|
}
|
||||||
|
|
||||||
private static final class SimpleTextFile implements FileUpload {
|
private static final class SimpleTextFile implements FileUpload {
|
||||||
|
|
||||||
private final User uploader;
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -7,9 +7,10 @@
|
|||||||
<body>
|
<body>
|
||||||
<wicket:panel>
|
<wicket:panel>
|
||||||
<div class="messageWrap">
|
<div class="messageWrap">
|
||||||
<div class="forumBlueBackground">
|
<div class="forumBlueBackground d-flex justify-content-between">
|
||||||
<!-- DATE ROW-->
|
<!-- DATE ROW-->
|
||||||
<wicket:container wicket:id="dateCreated"/>
|
<span wicket:id="dateCreated"></span>
|
||||||
|
<button wicket:id="delete" class="btn btn-sm btn-outline-danger ms-auto">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="forumGrayBackground">
|
<div class="forumGrayBackground">
|
||||||
<div class="vertAlign">
|
<div class="vertAlign">
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package se.su.dsv.scipro.forum.panels.threaded;
|
package se.su.dsv.scipro.forum.panels.threaded;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
import org.apache.wicket.Component;
|
import org.apache.wicket.Component;
|
||||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||||
|
import org.apache.wicket.markup.html.link.Link;
|
||||||
import org.apache.wicket.markup.html.panel.Panel;
|
import org.apache.wicket.markup.html.panel.Panel;
|
||||||
import org.apache.wicket.model.IModel;
|
import org.apache.wicket.model.IModel;
|
||||||
import org.apache.wicket.model.LambdaModel;
|
import org.apache.wicket.model.LambdaModel;
|
||||||
@ -11,9 +13,11 @@ import se.su.dsv.scipro.components.ListAdapterModel;
|
|||||||
import se.su.dsv.scipro.components.SmarterLinkMultiLineLabel;
|
import se.su.dsv.scipro.components.SmarterLinkMultiLineLabel;
|
||||||
import se.su.dsv.scipro.data.enums.DateStyle;
|
import se.su.dsv.scipro.data.enums.DateStyle;
|
||||||
import se.su.dsv.scipro.file.FileReference;
|
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.forum.dataobjects.ForumPost;
|
||||||
import se.su.dsv.scipro.profile.UserLinkPanel;
|
import se.su.dsv.scipro.profile.UserLinkPanel;
|
||||||
import se.su.dsv.scipro.repository.panels.ViewAttachmentPanel;
|
import se.su.dsv.scipro.repository.panels.ViewAttachmentPanel;
|
||||||
|
import se.su.dsv.scipro.session.SciProSession;
|
||||||
|
|
||||||
public class ForumPostPanel extends Panel {
|
public class ForumPostPanel extends Panel {
|
||||||
|
|
||||||
@ -22,6 +26,9 @@ public class ForumPostPanel extends Panel {
|
|||||||
public static final String CONTENT = "content";
|
public static final String CONTENT = "content";
|
||||||
public static final String ATTACHMENT = "attachment";
|
public static final String ATTACHMENT = "attachment";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BasicForumService basicForumService;
|
||||||
|
|
||||||
public ForumPostPanel(String id, final IModel<ForumPost> model) {
|
public ForumPostPanel(String id, final IModel<ForumPost> model) {
|
||||||
super(id);
|
super(id);
|
||||||
add(new UserLinkPanel(POSTED_BY, LambdaModel.of(model, ForumPost::getPostedBy, ForumPost::setPostedBy)));
|
add(new UserLinkPanel(POSTED_BY, LambdaModel.of(model, ForumPost::getPostedBy, ForumPost::setPostedBy)));
|
||||||
@ -62,5 +69,28 @@ public class ForumPostPanel extends Panel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add(
|
||||||
|
new Link<>("delete", model) {
|
||||||
|
@Override
|
||||||
|
public void onClick() {
|
||||||
|
ForumPost post = getModelObject();
|
||||||
|
basicForumService.deletePost(post);
|
||||||
|
onPostDeleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(allowDeletion() && basicForumService.canDelete(getModelObject()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean allowDeletion() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostDeleted() {}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package se.su.dsv.scipro.forum.panels.threaded;
|
package se.su.dsv.scipro.forum.panels.threaded;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||||
import org.apache.wicket.markup.html.basic.Label;
|
import org.apache.wicket.markup.html.basic.Label;
|
||||||
@ -15,6 +14,7 @@ import org.apache.wicket.model.LambdaModel;
|
|||||||
import org.apache.wicket.model.LoadableDetachableModel;
|
import org.apache.wicket.model.LoadableDetachableModel;
|
||||||
import se.su.dsv.scipro.components.DateLabel;
|
import se.su.dsv.scipro.components.DateLabel;
|
||||||
import se.su.dsv.scipro.data.enums.DateStyle;
|
import se.su.dsv.scipro.data.enums.DateStyle;
|
||||||
|
import se.su.dsv.scipro.forum.BasicForumService;
|
||||||
import se.su.dsv.scipro.forum.Discussable;
|
import se.su.dsv.scipro.forum.Discussable;
|
||||||
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||||
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
||||||
@ -23,6 +23,9 @@ import se.su.dsv.scipro.system.User;
|
|||||||
|
|
||||||
public class ThreadsOverviewPanel<A> extends Panel {
|
public class ThreadsOverviewPanel<A> extends Panel {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BasicForumService basicForumService;
|
||||||
|
|
||||||
public ThreadsOverviewPanel(
|
public ThreadsOverviewPanel(
|
||||||
final String id,
|
final String id,
|
||||||
final IModel<List<A>> model,
|
final IModel<List<A>> model,
|
||||||
@ -41,7 +44,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
|
|||||||
@Override
|
@Override
|
||||||
protected void onConfigure() {
|
protected void onConfigure() {
|
||||||
super.onConfigure();
|
super.onConfigure();
|
||||||
setVisibilityAllowed(discussion.getObject().hasAttachments());
|
setVisibilityAllowed(basicForumService.hasAttachments(discussion.getObject()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -80,7 +83,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
|
|||||||
BookmarkablePageLink<Void> newThreadLink(String id, IModel<A> thread);
|
BookmarkablePageLink<Void> newThreadLink(String id, IModel<A> thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LastPostColumn extends WebMarkupContainer {
|
private class LastPostColumn extends WebMarkupContainer {
|
||||||
|
|
||||||
public LastPostColumn(String id, final IModel<ForumThread> model) {
|
public LastPostColumn(String id, final IModel<ForumThread> model) {
|
||||||
super(id);
|
super(id);
|
||||||
@ -110,10 +113,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
|
|||||||
return new LoadableDetachableModel<>() {
|
return new LoadableDetachableModel<>() {
|
||||||
@Override
|
@Override
|
||||||
protected ForumPost load() {
|
protected ForumPost load() {
|
||||||
return Collections.max(
|
return basicForumService.getLastPost(model.getObject());
|
||||||
model.getObject().getPosts(),
|
|
||||||
Comparator.comparing(ForumPost::getDateCreated).thenComparing(ForumPost::getId)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,21 @@ public class ViewForumThreadPanel<A> extends GenericPanel<A> {
|
|||||||
new ListView<>(POST_LIST, new PostProvider()) {
|
new ListView<>(POST_LIST, new PostProvider()) {
|
||||||
@Override
|
@Override
|
||||||
protected void populateItem(ListItem<ForumPost> item) {
|
protected void populateItem(ListItem<ForumPost> item) {
|
||||||
item.add(new ForumPostPanel(POST, item.getModel()));
|
ListView<ForumPost> listView = this;
|
||||||
|
item.add(
|
||||||
|
new ForumPostPanel(POST, item.getModel()) {
|
||||||
|
@Override
|
||||||
|
protected boolean allowDeletion() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostDeleted() {
|
||||||
|
// Refresh the list of posts
|
||||||
|
listView.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -59,6 +59,11 @@ public class EditGroupPanel extends Panel {
|
|||||||
});
|
});
|
||||||
add(
|
add(
|
||||||
new ListView<>("available_projects", availableProjects) {
|
new ListView<>("available_projects", availableProjects) {
|
||||||
|
{
|
||||||
|
// must re-use list items to maintain form component (checkboxes) state
|
||||||
|
setReuseItems(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void populateItem(ListItem<Project> item) {
|
protected void populateItem(ListItem<Project> item) {
|
||||||
CheckBox checkbox = new CheckBox("selected", new SelectProjectModel(model, item.getModel()));
|
CheckBox checkbox = new CheckBox("selected", new SelectProjectModel(model, item.getModel()));
|
||||||
|
@ -9,6 +9,7 @@ import org.apache.wicket.model.Model;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import se.su.dsv.scipro.SciProTest;
|
import se.su.dsv.scipro.SciProTest;
|
||||||
import se.su.dsv.scipro.forum.Discussable;
|
import se.su.dsv.scipro.forum.Discussable;
|
||||||
@ -20,11 +21,13 @@ import se.su.dsv.scipro.system.User;
|
|||||||
public class ThreadsOverviewPanelTest extends SciProTest {
|
public class ThreadsOverviewPanelTest extends SciProTest {
|
||||||
|
|
||||||
private List<ForumThread> threads;
|
private List<ForumThread> threads;
|
||||||
|
private ForumPost post;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
ForumThread forumThread = createThread();
|
ForumThread forumThread = createThread();
|
||||||
threads = Arrays.asList(forumThread);
|
threads = Arrays.asList(forumThread);
|
||||||
|
Mockito.when(basicForumService.getLastPost(forumThread)).thenReturn(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,7 +57,7 @@ public class ThreadsOverviewPanelTest extends SciProTest {
|
|||||||
|
|
||||||
private ForumThread createThread() {
|
private ForumThread createThread() {
|
||||||
User bob = User.builder().firstName("Bob").lastName("the Builder").emailAddress("bob@building.com").build();
|
User bob = User.builder().firstName("Bob").lastName("the Builder").emailAddress("bob@building.com").build();
|
||||||
ForumPost post = new ForumPost();
|
post = new ForumPost();
|
||||||
post.setPostedBy(bob);
|
post.setPostedBy(bob);
|
||||||
ForumThread groupForumThread = new ForumThread();
|
ForumThread groupForumThread = new ForumThread();
|
||||||
groupForumThread.addPost(post);
|
groupForumThread.addPost(post);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user