task/3382: Harmonisera tabellnamn #6
@ -48,6 +48,7 @@ import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServ
|
|||||||
import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl;
|
import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl;
|
||||||
import se.su.dsv.scipro.peer.*;
|
import se.su.dsv.scipro.peer.*;
|
||||||
import se.su.dsv.scipro.plagiarism.*;
|
import se.su.dsv.scipro.plagiarism.*;
|
||||||
|
import se.su.dsv.scipro.project.ProjectNoteService;
|
||||||
import se.su.dsv.scipro.project.ProjectPeopleStatisticsService;
|
import se.su.dsv.scipro.project.ProjectPeopleStatisticsService;
|
||||||
import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl;
|
import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl;
|
||||||
import se.su.dsv.scipro.project.ProjectService;
|
import se.su.dsv.scipro.project.ProjectService;
|
||||||
@ -139,6 +140,7 @@ public class CoreModule extends AbstractModule {
|
|||||||
bind(FirstMeetingService.class).to(FirstMeetingServiceImpl.class);
|
bind(FirstMeetingService.class).to(FirstMeetingServiceImpl.class);
|
||||||
bind(FinalSeminarCreationSubscribers.class).asEagerSingleton();
|
bind(FinalSeminarCreationSubscribers.class).asEagerSingleton();
|
||||||
bind(ProjectPartnerRepository.class).to(ProjectPartnerRepositoryImpl.class);
|
bind(ProjectPartnerRepository.class).to(ProjectPartnerRepositoryImpl.class);
|
||||||
|
bind(ProjectNoteService.class).to(ProjectServiceImpl.class);
|
||||||
|
|
||||||
install(new PlagiarismModule());
|
install(new PlagiarismModule());
|
||||||
install(new NotificationModule());
|
install(new NotificationModule());
|
||||||
|
@ -25,4 +25,5 @@ public interface ProjectForumService {
|
|||||||
// TODO: Get these away from here
|
// TODO: Get these away from here
|
||||||
List<Pair<ProjectThread, ForumPost>> latestPost(Project a, int amount);
|
List<Pair<ProjectThread, ForumPost>> latestPost(Project a, int amount);
|
||||||
|
|
||||||
|
boolean hasUnreadThreads(Project project, User user);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,17 @@ public class ProjectForumServiceImpl implements ProjectForumService {
|
|||||||
return postRepository.latestPost(project, amount);
|
return postRepository.latestPost(project, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasUnreadThreads(Project project, User user) {
|
||||||
|
List<ProjectThread> threads = getThreads(project);
|
||||||
|
for (ProjectThread thread : threads) {
|
||||||
|
if (!basicForumService.isThreadRead(user, thread.getForumThread())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectThread findOne(long threadId) {
|
public ProjectThread findOne(long threadId) {
|
||||||
return projectThreadRepository.findOne(threadId);
|
return projectThreadRepository.findOne(threadId);
|
||||||
|
@ -86,6 +86,13 @@ public class Project extends DomainObject {
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private Language language;
|
private Language language;
|
||||||
|
|
||||||
|
@ElementCollection(fetch = FetchType.LAZY)
|
||||||
|
@CollectionTable(name = "project_user_note", joinColumns = @JoinColumn(name = "project_id"))
|
||||||
|
@Column(name = "note")
|
||||||
|
@SuppressWarnings("JpaDataSourceORMInspection") // false warning from IntelliJ for the @MapKeyJoinColumn
|
||||||
|
@MapKeyJoinColumn(name = "user_id")
|
||||||
|
private Map<User, String> userNotes = new HashMap<>();
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
void cleanTitle() {
|
void cleanTitle() {
|
||||||
@ -95,6 +102,14 @@ public class Project extends DomainObject {
|
|||||||
title = title.trim();
|
title = title.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<User, String> getUserNotes() {
|
||||||
|
return userNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserNotes(Map<User, String> userNotes) {
|
||||||
|
this.userNotes = userNotes;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFinalSeminarRuleExempted() {
|
public boolean isFinalSeminarRuleExempted() {
|
||||||
return finalSeminarRuleExempted;
|
return finalSeminarRuleExempted;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package se.su.dsv.scipro.project;
|
||||||
|
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
|
public interface ProjectNoteService {
|
||||||
|
String getUserNote(Project project, User user);
|
||||||
|
|
||||||
|
void setUserNote(Project project, User user, String note);
|
||||||
|
}
|
@ -11,4 +11,8 @@ import java.util.List;
|
|||||||
@Transactional
|
@Transactional
|
||||||
public interface ProjectRepo extends JpaRepository<Project, Long>, QueryDslPredicateExecutor<Project> {
|
public interface ProjectRepo extends JpaRepository<Project, Long>, QueryDslPredicateExecutor<Project> {
|
||||||
List<User> findMultipleAuthors(Collection<Project> projects);
|
List<User> findMultipleAuthors(Collection<Project> projects);
|
||||||
|
|
||||||
|
String getUserNoteForProject(Project project, User user);
|
||||||
|
|
||||||
|
void setUserNoteForProject(Project project, User user, String note);
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package se.su.dsv.scipro.project;
|
package se.su.dsv.scipro.project;
|
||||||
|
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
import se.su.dsv.scipro.system.GenericRepo;
|
import se.su.dsv.scipro.system.GenericRepo;
|
||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
@ -30,4 +31,16 @@ public class ProjectRepoImpl extends GenericRepo<Project, Long> implements Proje
|
|||||||
query.setParameter("projects", projects);
|
query.setParameter("projects", projects);
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserNoteForProject(Project project, User user) {
|
||||||
|
return project.getUserNotes().get(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void setUserNoteForProject(Project project, User user, String note) {
|
||||||
|
project.getUserNotes().put(user, note);
|
||||||
|
save(project);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import java.time.Duration;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectService {
|
public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectService, ProjectNoteService {
|
||||||
|
|
||||||
public static final int MIN_TITLE_LENGTH = 3;
|
public static final int MIN_TITLE_LENGTH = 3;
|
||||||
private final ProjectRepo projectRepo;
|
private final ProjectRepo projectRepo;
|
||||||
@ -175,6 +175,16 @@ public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> imple
|
|||||||
return completed;
|
return completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserNote(Project project, User user) {
|
||||||
|
return projectRepo.getUserNoteForProject(project, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserNote(Project project, User user, String note) {
|
||||||
|
projectRepo.setUserNoteForProject(project, user, note);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Project> findAll(Filter filter, Pageable pageable) {
|
public List<Project> findAll(Filter filter, Pageable pageable) {
|
||||||
return findAll(toPredicate(filter), pageable);
|
return findAll(toPredicate(filter), pageable);
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package se.su.dsv.scipro.settings.dataobjects;
|
||||||
|
|
||||||
|
public enum SupervisorProjectNoteDisplay {
|
||||||
|
COMPACT, FULL
|
||||||
|
}
|
@ -79,6 +79,11 @@ public class UserProfile extends DomainObject {
|
|||||||
)
|
)
|
||||||
private Collection<ProjectType> defaultProjectTypeFilter = new ArrayList<>();
|
private Collection<ProjectType> defaultProjectTypeFilter = new ArrayList<>();
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(name = "supervisor_project_note_display")
|
||||||
|
private SupervisorProjectNoteDisplay supervisorProjectNoteDisplay = SupervisorProjectNoteDisplay.COMPACT;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return this.id;
|
return this.id;
|
||||||
@ -168,6 +173,14 @@ public class UserProfile extends DomainObject {
|
|||||||
this.selectedRole = selectedRole;
|
this.selectedRole = selectedRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SupervisorProjectNoteDisplay getSupervisorProjectNoteDisplay() {
|
||||||
|
return supervisorProjectNoteDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupervisorProjectNoteDisplay(SupervisorProjectNoteDisplay supervisorProjectNoteDisplay) {
|
||||||
|
this.supervisorProjectNoteDisplay = supervisorProjectNoteDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "UserProfile(id=" + this.getId() + ", user=" + this.getUser() + ", skypeId=" + this.getSkypeId() + ", phoneNumber=" + this.getPhoneNumber() + ", otherInfo=" + this.getOtherInfo() + ", mailCompilation=" + this.isMailCompilation() + ", defaultProjectStatusFilter=" + this.getDefaultProjectStatusFilter() + ", defaultProjectTeamMemberRolesFilter=" + this.getDefaultProjectTeamMemberRolesFilter() + ", defaultSupervisorFilter=" + this.isDefaultSupervisorFilter() + ", defaultProjectTypeFilter=" + this.getDefaultProjectTypeFilter() + ", selectedRole=" + this.getSelectedRole() + ")";
|
return "UserProfile(id=" + this.getId() + ", user=" + this.getUser() + ", skypeId=" + this.getSkypeId() + ", phoneNumber=" + this.getPhoneNumber() + ", otherInfo=" + this.getOtherInfo() + ", mailCompilation=" + this.isMailCompilation() + ", defaultProjectStatusFilter=" + this.getDefaultProjectStatusFilter() + ", defaultProjectTeamMemberRolesFilter=" + this.getDefaultProjectTeamMemberRolesFilter() + ", defaultSupervisorFilter=" + this.isDefaultSupervisorFilter() + ", defaultProjectTypeFilter=" + this.getDefaultProjectTypeFilter() + ", selectedRole=" + this.getSelectedRole() + ")";
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `project_user_note` (
|
||||||
|
`project_id` bigint NOT NULL,
|
||||||
|
`user_id` bigint NOT NULL,
|
||||||
|
`note` text NULL,
|
||||||
|
PRIMARY KEY (`project_id`, `user_id`),
|
||||||
|
CONSTRAINT `FK_project_user_note_project` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `FK_project_user_note_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `user_profile`
|
||||||
|
ADD COLUMN `supervisor_project_note_display` VARCHAR(15) NOT NULL DEFAULT 'COMPACT';
|
@ -20,6 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
import static org.hamcrest.Matchers.hasItem;
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class ProjectForumServiceImplTest extends ForumModuleTest {
|
public class ProjectForumServiceImplTest extends ForumModuleTest {
|
||||||
|
|
||||||
@ -29,23 +30,24 @@ public class ProjectForumServiceImplTest extends ForumModuleTest {
|
|||||||
ProjectForumService service;
|
ProjectForumService service;
|
||||||
|
|
||||||
private Project project;
|
private Project project;
|
||||||
private User user;
|
private User author;
|
||||||
|
private User supervisor;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
ProjectType projectType = new ProjectType(DegreeType.BACHELOR, "Some project type", "Some description");
|
ProjectType projectType = new ProjectType(DegreeType.BACHELOR, "Some project type", "Some description");
|
||||||
projectType.addModule(ProjectModule.FORUM);
|
projectType.addModule(ProjectModule.FORUM);
|
||||||
save(projectType);
|
save(projectType);
|
||||||
final User supervisor = save(User.builder().firstName("Bob").lastName("The Builder").emailAddress("bob@example.com").build());
|
supervisor = save(User.builder().firstName("Bob").lastName("The Builder").emailAddress("bob@example.com").build());
|
||||||
project = Project.builder().title("Some title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(supervisor).build();
|
project = Project.builder().title("Some title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(supervisor).build();
|
||||||
save(project);
|
save(project);
|
||||||
user = User.builder().firstName("Stina").lastName("Student").emailAddress("stina@example.com").build();
|
author = User.builder().firstName("Stina").lastName("Student").emailAddress("stina@example.com").build();
|
||||||
save(user);
|
save(author);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadThread() {
|
public void testLoadThread() {
|
||||||
final ProjectThread thread = service.createThread(project, user, "subject", "content", Set.of());
|
final ProjectThread thread = service.createThread(project, author, "subject", "content", Set.of());
|
||||||
ProjectThread serviceThread = service.findOne(thread.getId());
|
ProjectThread serviceThread = service.findOne(thread.getId());
|
||||||
|
|
||||||
assertEquals(thread, serviceThread);
|
assertEquals(thread, serviceThread);
|
||||||
@ -55,17 +57,17 @@ public class ProjectForumServiceImplTest extends ForumModuleTest {
|
|||||||
public void testCreateThreadWithPostAttachment() throws Exception {
|
public void testCreateThreadWithPostAttachment() throws Exception {
|
||||||
final String file = "attachment.txt";
|
final String file = "attachment.txt";
|
||||||
try (var is = ProjectForumServiceImplTest.class.getResourceAsStream(file)) {
|
try (var is = ProjectForumServiceImplTest.class.getResourceAsStream(file)) {
|
||||||
final StreamingUpload upload = new StreamingUpload(file, "text/plain", user, 2, is);
|
final StreamingUpload upload = new StreamingUpload(file, "text/plain", author, 2, is);
|
||||||
final ProjectThread thread = service.createThread(project, user, SUBJECT, CONTENT, Set.of(Attachment.newUpload(upload)));
|
final ProjectThread thread = service.createThread(project, author, SUBJECT, CONTENT, Set.of(Attachment.newUpload(upload)));
|
||||||
|
|
||||||
assertNewForumThread(thread, project, user, SUBJECT, CONTENT, file);
|
assertNewForumThread(thread, project, author, SUBJECT, CONTENT, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetPostPageByForumThread() {
|
public void testGetPostPageByForumThread() {
|
||||||
final ProjectThread thread = service.createThread(project, user, "subject", "content", Set.of());
|
final ProjectThread thread = service.createThread(project, author, "subject", "content", Set.of());
|
||||||
final ForumPost reply = service.createReply(thread, user, "reply", Set.of());
|
final ForumPost reply = service.createReply(thread, author, "reply", Set.of());
|
||||||
|
|
||||||
|
|
||||||
List<ForumPost> servicePage = service.getPosts(thread);
|
List<ForumPost> servicePage = service.getPosts(thread);
|
||||||
@ -76,8 +78,8 @@ public class ProjectForumServiceImplTest extends ForumModuleTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetThreadsByProject() {
|
public void testGetThreadsByProject() {
|
||||||
final ProjectThread thread1 = service.createThread(project, user, "subject 1", "content", Set.of());
|
final ProjectThread thread1 = service.createThread(project, author, "subject 1", "content", Set.of());
|
||||||
final ProjectThread thread2 = service.createThread(project, user, "subject 2", "content", Set.of());
|
final ProjectThread thread2 = service.createThread(project, author, "subject 2", "content", Set.of());
|
||||||
|
|
||||||
List<ProjectThread> serviceThreads = service.getThreads(project);
|
List<ProjectThread> serviceThreads = service.getThreads(project);
|
||||||
|
|
||||||
@ -86,6 +88,16 @@ public class ProjectForumServiceImplTest extends ForumModuleTest {
|
|||||||
assertThat(serviceThreads, hasSize(2));
|
assertThat(serviceThreads, hasSize(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void supervisor_has_unread_forum_threads_after_student_replies() {
|
||||||
|
final ProjectThread thread = service.createThread(project, supervisor, "subject", "content", Set.of());
|
||||||
|
service.createReply(thread, author, "reply", Set.of());
|
||||||
|
|
||||||
|
boolean hasUnreadThreads = service.hasUnreadThreads(project, supervisor);
|
||||||
|
|
||||||
|
assertTrue(hasUnreadThreads);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertNewForumThread(
|
private void assertNewForumThread(
|
||||||
ProjectThread thread, Project project, User user, String subject, String content, String attachmentFileName) {
|
ProjectThread thread, Project project, User user, String subject, String content, String attachmentFileName) {
|
||||||
assertEquals(project, thread.getProject(), "Thread created for the wrong project");
|
assertEquals(project, thread.getProject(), "Thread created for the wrong project");
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package se.su.dsv.scipro.components;
|
||||||
|
|
||||||
|
import org.apache.wicket.markup.html.basic.Label;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
import org.apache.wicket.util.convert.IConverter;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class MaxLengthLabel extends Label {
|
||||||
|
private final IModel<Integer> maxLengthModel;
|
||||||
|
|
||||||
|
public MaxLengthLabel(String id, IModel<String> dataModel, IModel<Integer> maxLength) {
|
||||||
|
super(id, dataModel);
|
||||||
|
this.maxLengthModel = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IConverter<?> createConverter(Class<?> type) {
|
||||||
|
return new MaxLengthConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MaxLengthConverter implements IConverter<String> {
|
||||||
|
@Override
|
||||||
|
public String convertToObject(String s, Locale locale) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertToString(String o, Locale locale) {
|
||||||
|
Integer maxLength = maxLengthModel.getObject();
|
||||||
|
if (o.length() > maxLength) {
|
||||||
|
return o.substring(0, maxLength) + "...";
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package se.su.dsv.scipro.components;
|
package se.su.dsv.scipro.components;
|
||||||
|
|
||||||
import org.apache.wicket.Component;
|
import org.apache.wicket.Component;
|
||||||
|
import org.apache.wicket.ajax.AjaxEventBehavior;
|
||||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||||
import org.apache.wicket.behavior.AttributeAppender;
|
import org.apache.wicket.behavior.AttributeAppender;
|
||||||
import org.apache.wicket.markup.ComponentTag;
|
import org.apache.wicket.markup.ComponentTag;
|
||||||
@ -9,6 +10,7 @@ import org.apache.wicket.markup.html.basic.Label;
|
|||||||
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.Model;
|
import org.apache.wicket.model.Model;
|
||||||
|
import org.danekja.java.util.function.serializable.SerializableConsumer;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@ -83,4 +85,13 @@ public class ModalWindowPlus extends Panel {
|
|||||||
component.setOutputMarkupPlaceholderTag(true);
|
component.setOutputMarkupPlaceholderTag(true);
|
||||||
replace(component);
|
replace(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onClose(SerializableConsumer<AjaxRequestTarget> onClose) {
|
||||||
|
add(new AjaxEventBehavior("hidden.bs.modal") {
|
||||||
|
@Override
|
||||||
|
protected void onEvent(AjaxRequestTarget target) {
|
||||||
|
onClose.accept(target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public abstract class AbstractReadStatePanel extends Panel {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(final Optional<AjaxRequestTarget> target) {
|
public void onClick(final Optional<AjaxRequestTarget> target) {
|
||||||
target.ifPresent(t -> {
|
target.ifPresent(t -> {
|
||||||
toggleReadState(t);
|
onFlagClick(t);
|
||||||
t.add(icon);
|
t.add(icon);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ public abstract class AbstractReadStatePanel extends Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isRead();
|
protected abstract boolean isRead();
|
||||||
protected abstract void toggleReadState(final AjaxRequestTarget target);
|
protected abstract void onFlagClick(final AjaxRequestTarget target);
|
||||||
|
|
||||||
public static final String TOGGLE = "toggle";
|
public static final String TOGGLE = "toggle";
|
||||||
static final String ICON = "icon";
|
static final String ICON = "icon";
|
||||||
|
@ -31,7 +31,7 @@ public class ThreadReadStatePanel extends AbstractReadStatePanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toggleReadState(final AjaxRequestTarget target) {
|
protected void onFlagClick(final AjaxRequestTarget target) {
|
||||||
boolean read = isRead();
|
boolean read = isRead();
|
||||||
basicForumService.setThreadRead(SciProSession.get().getUser(), model.getObject(), !read);
|
basicForumService.setThreadRead(SciProSession.get().getUser(), model.getObject(), !read);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ public class NotificationDataPanel extends Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toggleReadState(final AjaxRequestTarget target) {
|
protected void onFlagClick(final AjaxRequestTarget target) {
|
||||||
Notification notification = rowModel.getObject();
|
Notification notification = rowModel.getObject();
|
||||||
notification.setUnread(!notification.isUnread());
|
notification.setUnread(!notification.isUnread());
|
||||||
notificationService.save(notification);
|
notificationService.save(notification);
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
||||||
|
<body>
|
||||||
|
<wicket:panel>
|
||||||
|
<div wicket:id="edit_note_modal"></div>
|
||||||
|
<span wicket:id="shortened_note"></span>
|
||||||
|
<wicket:container wicket:id="full_note"></wicket:container>
|
||||||
|
<a wicket:id="view_note"><wicket:message key="note.view.edit"/></a>
|
||||||
|
</wicket:panel>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,2 @@
|
|||||||
|
note.modal.title=View/edit note for ${title}
|
||||||
|
note.view.edit=View/edit note
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
||||||
|
<body>
|
||||||
|
<wicket:panel>
|
||||||
|
<form wicket:id="form">
|
||||||
|
<div wicket:id="feedback"></div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label wicket:for="note" class="sr-only">Note</label>
|
||||||
|
<textarea wicket:id="note" rows="20" class="form-control"></textarea>
|
||||||
|
</div>
|
||||||
|
<button wicket:id="save" type="submit" class="btn btn-primary">Save</button>
|
||||||
|
</form>
|
||||||
|
</wicket:panel>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,129 @@
|
|||||||
|
package se.su.dsv.scipro.supervisor.panels;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||||
|
import org.apache.wicket.ajax.markup.html.AjaxLink;
|
||||||
|
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
|
||||||
|
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
|
||||||
|
import org.apache.wicket.extensions.markup.html.repeater.data.table.export.AbstractExportableColumn;
|
||||||
|
import org.apache.wicket.feedback.FencedFeedbackPanel;
|
||||||
|
import org.apache.wicket.injection.Injector;
|
||||||
|
import org.apache.wicket.markup.html.basic.MultiLineLabel;
|
||||||
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
|
import org.apache.wicket.markup.html.form.TextArea;
|
||||||
|
import org.apache.wicket.markup.html.panel.GenericPanel;
|
||||||
|
import org.apache.wicket.markup.repeater.Item;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
import org.apache.wicket.model.LoadableDetachableModel;
|
||||||
|
import org.apache.wicket.model.Model;
|
||||||
|
import org.apache.wicket.model.StringResourceModel;
|
||||||
|
import se.su.dsv.scipro.components.LargeModalWindow;
|
||||||
|
import se.su.dsv.scipro.components.MaxLengthLabel;
|
||||||
|
import se.su.dsv.scipro.components.ModalWindowPlus;
|
||||||
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.project.ProjectNoteService;
|
||||||
|
import se.su.dsv.scipro.settings.dataobjects.SupervisorProjectNoteDisplay;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
|
public class ProjectNoteColumn extends AbstractExportableColumn<Project, String> {
|
||||||
|
@Inject
|
||||||
|
private ProjectNoteService projectNoteService;
|
||||||
|
|
||||||
|
private final IModel<User> user;
|
||||||
|
private final IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel;
|
||||||
|
|
||||||
|
public ProjectNoteColumn(IModel<String> displayModel, IModel<User> user,
|
||||||
|
IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel) {
|
||||||
|
super(displayModel);
|
||||||
|
Injector.get().inject(this);
|
||||||
|
this.supervisorProjectNoteDisplayModel = supervisorProjectNoteDisplayModel;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IModel<String> getDataModel(IModel<Project> rowModel) {
|
||||||
|
return LoadableDetachableModel.of(() -> projectNoteService.getUserNote(
|
||||||
|
rowModel.getObject(),
|
||||||
|
user.getObject()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateItem(
|
||||||
|
Item<ICellPopulator<Project>> cellItem,
|
||||||
|
String componentId,
|
||||||
|
IModel<Project> rowModel)
|
||||||
|
{
|
||||||
|
cellItem.add(new ViewAndEditNoteCellPanel(componentId, rowModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewAndEditNoteCellPanel extends GenericPanel<Project> {
|
||||||
|
public ViewAndEditNoteCellPanel(String id, IModel<Project> model) {
|
||||||
|
super(id, model);
|
||||||
|
|
||||||
|
ModalWindowPlus modal = new LargeModalWindow("edit_note_modal");
|
||||||
|
modal.setTitle(new StringResourceModel("note.modal.title", this, model));
|
||||||
|
modal.setContent(componentId -> new ViewAndEditNoteForm(componentId, model));
|
||||||
|
add(modal);
|
||||||
|
|
||||||
|
setOutputMarkupId(true);
|
||||||
|
modal.onClose(target -> target.add(this));
|
||||||
|
|
||||||
|
add(new MaxLengthLabel("shortened_note", getDataModel(model), Model.of(100)) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisibilityAllowed(supervisorProjectNoteDisplayModel.getObject() == SupervisorProjectNoteDisplay.COMPACT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(new MultiLineLabel("full_note", getDataModel(model)) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisibilityAllowed(supervisorProjectNoteDisplayModel.getObject() == SupervisorProjectNoteDisplay.FULL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AjaxLink<Object> noteLink = new AjaxLink<>("view_note") {
|
||||||
|
@Override
|
||||||
|
public void onClick(AjaxRequestTarget target) {
|
||||||
|
modal.show(target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add(noteLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewAndEditNoteForm extends GenericPanel<Project> {
|
||||||
|
public ViewAndEditNoteForm(String id, IModel<Project> project) {
|
||||||
|
super(id, project);
|
||||||
|
|
||||||
|
IModel<String> note = getDataModel(project);
|
||||||
|
|
||||||
|
Form<Project> form = new Form<>("form", project) {
|
||||||
|
@Override
|
||||||
|
protected void onSubmit() {
|
||||||
|
projectNoteService.setUserNote(
|
||||||
|
project.getObject(),
|
||||||
|
user.getObject(),
|
||||||
|
note.getObject()
|
||||||
|
);
|
||||||
|
success("Note saved at " + LocalTime.now().truncatedTo(ChronoUnit.SECONDS));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
add(form);
|
||||||
|
|
||||||
|
form.add(new FencedFeedbackPanel("feedback", form));
|
||||||
|
|
||||||
|
form.add(new TextArea<>("note", note));
|
||||||
|
form.add(new AjaxSubmitLink("save") {
|
||||||
|
@Override
|
||||||
|
protected void onAfterSubmit(AjaxRequestTarget target) {
|
||||||
|
target.add(form);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,10 @@
|
|||||||
</strong>
|
</strong>
|
||||||
<div wicket:id="projectTypes"></div>
|
<div wicket:id="projectTypes"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<fieldset class="col-6 col-md-3 col-lg-2">
|
||||||
|
<legend>Note</legend>
|
||||||
|
<div wicket:id="note_display"></div>
|
||||||
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package se.su.dsv.scipro.supervisor.panels;
|
package se.su.dsv.scipro.supervisor.panels;
|
||||||
|
|
||||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||||
|
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
|
||||||
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
|
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
|
||||||
|
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
|
||||||
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
|
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
|
||||||
|
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
|
||||||
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
|
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
|
||||||
import org.apache.wicket.extensions.markup.html.repeater.data.table.LambdaColumn;
|
import org.apache.wicket.extensions.markup.html.repeater.data.table.LambdaColumn;
|
||||||
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
|
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
|
||||||
@ -10,8 +13,10 @@ import org.apache.wicket.markup.html.form.EnumChoiceRenderer;
|
|||||||
import org.apache.wicket.markup.html.form.Form;
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
import org.apache.wicket.markup.html.form.LambdaChoiceRenderer;
|
import org.apache.wicket.markup.html.form.LambdaChoiceRenderer;
|
||||||
import org.apache.wicket.markup.html.panel.Panel;
|
import org.apache.wicket.markup.html.panel.Panel;
|
||||||
|
import org.apache.wicket.markup.repeater.Item;
|
||||||
import org.apache.wicket.model.IModel;
|
import org.apache.wicket.model.IModel;
|
||||||
import org.apache.wicket.model.LambdaModel;
|
import org.apache.wicket.model.LambdaModel;
|
||||||
|
import org.apache.wicket.model.LoadableDetachableModel;
|
||||||
import org.apache.wicket.model.Model;
|
import org.apache.wicket.model.Model;
|
||||||
import se.su.dsv.scipro.components.*;
|
import se.su.dsv.scipro.components.*;
|
||||||
import se.su.dsv.scipro.components.datatables.MultipleUsersColumn;
|
import se.su.dsv.scipro.components.datatables.MultipleUsersColumn;
|
||||||
@ -19,11 +24,15 @@ import se.su.dsv.scipro.components.datatables.UserColumn;
|
|||||||
import se.su.dsv.scipro.dataproviders.FilteredDataProvider;
|
import se.su.dsv.scipro.dataproviders.FilteredDataProvider;
|
||||||
import se.su.dsv.scipro.datatables.project.ProjectStateColumn;
|
import se.su.dsv.scipro.datatables.project.ProjectStateColumn;
|
||||||
import se.su.dsv.scipro.datatables.project.ProjectTitleColumn;
|
import se.su.dsv.scipro.datatables.project.ProjectTitleColumn;
|
||||||
|
import se.su.dsv.scipro.forum.ProjectForumService;
|
||||||
|
import se.su.dsv.scipro.forum.pages.threaded.SupervisorThreadedForumPage;
|
||||||
|
import se.su.dsv.scipro.forum.panels.AbstractReadStatePanel;
|
||||||
import se.su.dsv.scipro.project.Project;
|
import se.su.dsv.scipro.project.Project;
|
||||||
import se.su.dsv.scipro.project.ProjectService;
|
import se.su.dsv.scipro.project.ProjectService;
|
||||||
import se.su.dsv.scipro.project.ProjectStatus;
|
import se.su.dsv.scipro.project.ProjectStatus;
|
||||||
import se.su.dsv.scipro.project.ProjectTeamMemberRoles;
|
import se.su.dsv.scipro.project.ProjectTeamMemberRoles;
|
||||||
import se.su.dsv.scipro.session.SciProSession;
|
import se.su.dsv.scipro.session.SciProSession;
|
||||||
|
import se.su.dsv.scipro.settings.dataobjects.SupervisorProjectNoteDisplay;
|
||||||
import se.su.dsv.scipro.settings.dataobjects.UserProfile;
|
import se.su.dsv.scipro.settings.dataobjects.UserProfile;
|
||||||
import se.su.dsv.scipro.springdata.services.UserProfileService;
|
import se.su.dsv.scipro.springdata.services.UserProfileService;
|
||||||
import se.su.dsv.scipro.system.ProjectType;
|
import se.su.dsv.scipro.system.ProjectType;
|
||||||
@ -51,9 +60,12 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
private ProjectService projectService;
|
private ProjectService projectService;
|
||||||
@Inject
|
@Inject
|
||||||
private UserProfileService profileService;
|
private UserProfileService profileService;
|
||||||
|
@Inject
|
||||||
|
private ProjectForumService projectForumService;
|
||||||
|
|
||||||
private ExportableDataPanel dataPanel;
|
private ExportableDataPanel dataPanel;
|
||||||
private ProjectService.Filter filter = new ProjectService.Filter();
|
private ProjectService.Filter filter = new ProjectService.Filter();
|
||||||
|
private IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel = new Model<>();
|
||||||
|
|
||||||
public SupervisorMyProjectsPanel(String id) {
|
public SupervisorMyProjectsPanel(String id) {
|
||||||
super(id);
|
super(id);
|
||||||
@ -72,6 +84,7 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
private List<IColumn<Project, String>> createColumns() {
|
private List<IColumn<Project, String>> createColumns() {
|
||||||
List<IColumn<Project, String>> columns = new ArrayList<>();
|
List<IColumn<Project, String>> columns = new ArrayList<>();
|
||||||
columns.add(new ProjectStateColumn(Model.of("State"), "stateOfMind"));
|
columns.add(new ProjectStateColumn(Model.of("State"), "stateOfMind"));
|
||||||
|
columns.add(new ProjectForumStateColumn(Model.of("Forum")));
|
||||||
columns.add(new TemporalColumn<>(Model.of("Started"), "startDate", Project::getStartDate));
|
columns.add(new TemporalColumn<>(Model.of("Started"), "startDate", Project::getStartDate));
|
||||||
columns.add(new LambdaColumn<>(Model.of("Type"), "projectType.name", Project::getProjectTypeName));
|
columns.add(new LambdaColumn<>(Model.of("Type"), "projectType.name", Project::getProjectTypeName));
|
||||||
columns.add(new ProjectTitleColumn(Model.of("Title"), "title"));
|
columns.add(new ProjectTitleColumn(Model.of("Title"), "title"));
|
||||||
@ -81,6 +94,7 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
return new ListAdapterModel<>(rowModel.map(Project::getProjectParticipants));
|
return new ListAdapterModel<>(rowModel.map(Project::getProjectParticipants));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
columns.add(new ProjectNoteColumn(Model.of("Note"), LoadableDetachableModel.of(this::currentUser), supervisorProjectNoteDisplayModel));
|
||||||
columns.add(new UserColumn<>(Model.of("Head supervisor"), "headSupervisor.fullName", Project::getHeadSupervisor));
|
columns.add(new UserColumn<>(Model.of("Head supervisor"), "headSupervisor.fullName", Project::getHeadSupervisor));
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
@ -103,6 +117,7 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
filter.setRoles(userProfile.getDefaultProjectTeamMemberRolesFilter());
|
filter.setRoles(userProfile.getDefaultProjectTeamMemberRolesFilter());
|
||||||
filter.setFilterSupervisor(userProfile.isDefaultSupervisorFilter());
|
filter.setFilterSupervisor(userProfile.isDefaultSupervisorFilter());
|
||||||
filter.setProjectTypes(userProfile.getDefaultProjectTypeFilter());
|
filter.setProjectTypes(userProfile.getDefaultProjectTypeFilter());
|
||||||
|
supervisorProjectNoteDisplayModel.setObject(userProfile.getSupervisorProjectNoteDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
private User currentUser() {
|
private User currentUser() {
|
||||||
@ -146,6 +161,19 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
updateProfileWithCurrentFilter();
|
updateProfileWithCurrentFilter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
BootstrapRadioChoice<SupervisorProjectNoteDisplay> noteDisplay = new BootstrapRadioChoice<>(
|
||||||
|
"note_display",
|
||||||
|
supervisorProjectNoteDisplayModel,
|
||||||
|
List.of(SupervisorProjectNoteDisplay.values()),
|
||||||
|
new EnumChoiceRenderer<>(this));
|
||||||
|
noteDisplay.add(new AjaxFormChoiceComponentUpdatingBehavior() {
|
||||||
|
@Override
|
||||||
|
public void onUpdate(AjaxRequestTarget target) {
|
||||||
|
target.add(dataPanel);
|
||||||
|
updateProfileWithCurrentFilter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(noteDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProfileWithCurrentFilter() {
|
private void updateProfileWithCurrentFilter() {
|
||||||
@ -154,7 +182,33 @@ public class SupervisorMyProjectsPanel extends Panel {
|
|||||||
userProfile.setDefaultProjectTeamMemberRolesFilter(filter.getRoles());
|
userProfile.setDefaultProjectTeamMemberRolesFilter(filter.getRoles());
|
||||||
userProfile.setDefaultSupervisorFilter(filter.isFilterSupervisor());
|
userProfile.setDefaultSupervisorFilter(filter.isFilterSupervisor());
|
||||||
userProfile.setDefaultProjectTypeFilter(filter.getProjectTypes());
|
userProfile.setDefaultProjectTypeFilter(filter.getProjectTypes());
|
||||||
|
userProfile.setSupervisorProjectNoteDisplay(supervisorProjectNoteDisplayModel.getObject());
|
||||||
profileService.save(userProfile);
|
profileService.save(userProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ProjectForumStateColumn extends AbstractColumn<Project, String> {
|
||||||
|
public ProjectForumStateColumn(IModel<String> label) {
|
||||||
|
super(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populateItem(Item<ICellPopulator<Project>> item, String id, IModel<Project> projectModel) {
|
||||||
|
item.add(new AbstractReadStatePanel(id) {
|
||||||
|
@Override
|
||||||
|
protected boolean isRead() {
|
||||||
|
return !projectForumService.hasUnreadThreads(
|
||||||
|
projectModel.getObject(),
|
||||||
|
SciProSession.get().getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFlagClick(AjaxRequestTarget target) {
|
||||||
|
setResponsePage(
|
||||||
|
SupervisorThreadedForumPage.class,
|
||||||
|
SupervisorThreadedForumPage.getPageParameters(projectModel.getObject()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,6 @@ ProjectTeamMemberRoles.CO_SUPERVISOR= Co-Supervisor
|
|||||||
ProjectStatus.ACTIVE= Active
|
ProjectStatus.ACTIVE= Active
|
||||||
ProjectStatus.INACTIVE= Inactive
|
ProjectStatus.INACTIVE= Inactive
|
||||||
ProjectStatus.COMPLETED= Completed
|
ProjectStatus.COMPLETED= Completed
|
||||||
|
|
||||||
|
SupervisorProjectNoteDisplay.COMPACT=Compact
|
||||||
|
SupervisorProjectNoteDisplay.FULL=Full
|
||||||
|
@ -87,6 +87,7 @@ import se.su.dsv.scipro.peer.PerformReviewService;
|
|||||||
import se.su.dsv.scipro.plagiarism.PlagiarismControl;
|
import se.su.dsv.scipro.plagiarism.PlagiarismControl;
|
||||||
import se.su.dsv.scipro.plagiarism.urkund.UrkundService;
|
import se.su.dsv.scipro.plagiarism.urkund.UrkundService;
|
||||||
import se.su.dsv.scipro.profiles.CurrentProfile;
|
import se.su.dsv.scipro.profiles.CurrentProfile;
|
||||||
|
import se.su.dsv.scipro.project.ProjectNoteService;
|
||||||
import se.su.dsv.scipro.project.ProjectPeopleStatisticsService;
|
import se.su.dsv.scipro.project.ProjectPeopleStatisticsService;
|
||||||
import se.su.dsv.scipro.project.ProjectService;
|
import se.su.dsv.scipro.project.ProjectService;
|
||||||
import se.su.dsv.scipro.project.pages.ProjectStartPage;
|
import se.su.dsv.scipro.project.pages.ProjectStartPage;
|
||||||
@ -355,6 +356,8 @@ public abstract class SciProTest {
|
|||||||
protected ExaminerTimelineService examinerTimelineService;
|
protected ExaminerTimelineService examinerTimelineService;
|
||||||
@Mock
|
@Mock
|
||||||
protected NationalSubjectCategoryService nationalSubjectCategoryService;
|
protected NationalSubjectCategoryService nationalSubjectCategoryService;
|
||||||
|
@Mock
|
||||||
|
protected ProjectNoteService projectNoteService;
|
||||||
|
|
||||||
protected WicketTester tester;
|
protected WicketTester tester;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user