From afe02ce5d2e226be057b7f952567894a40fc4633 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Thu, 15 May 2025 11:06:11 -0700 Subject: [PATCH 01/22] Create new account for survey unit link --- .../survey/SurveyAPIController.java | 96 +++++++++++++++++++ .../student/impl/StudentServiceImpl.java | 2 + 2 files changed, 98 insertions(+) create mode 100644 src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java new file mode 100644 index 000000000..0a7f5bdbf --- /dev/null +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -0,0 +1,96 @@ +package org.wise.portal.presentation.web.controllers.survey; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.wise.portal.dao.ObjectNotFoundException; +import org.wise.portal.domain.PeriodNotFoundException; +import org.wise.portal.domain.RunHasEndedException; +import org.wise.portal.domain.StudentUserAlreadyAssociatedWithRunException; +import org.wise.portal.domain.authentication.Gender; +import org.wise.portal.domain.authentication.impl.StudentUserDetails; +import org.wise.portal.domain.project.impl.Projectcode; +import org.wise.portal.domain.run.Run; +import org.wise.portal.domain.user.User; +import org.wise.portal.service.authentication.DuplicateUsernameException; +import org.wise.portal.service.run.RunService; +import org.wise.portal.service.student.StudentService; +import org.wise.portal.service.user.UserService; +import org.wise.portal.service.workgroup.WorkgroupService; + +import java.io.IOException; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +@RestController +@RequestMapping("/api/survey") +public class SurveyAPIController { + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RunService runService; + + @Autowired + private StudentService studentService; + + @Autowired + private UserService userService; + + @Autowired + private WorkgroupService workgroupService; + + @GetMapping("/launch/{p}") + public void launchSurveyRun(@PathVariable String p, HttpServletResponse response, HttpServletRequest request) + throws IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { + + Projectcode projectCode = new Projectcode(p); + Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); + User user = this.createNewStudentAccount(); + loginStudent(request, user); + studentService.addStudentToRun(user, projectCode); + createWorkgroupForUser(user, run); + response.sendRedirect("/student/unit/" + run.getId()); + } + + private void createWorkgroupForUser(User user, Run run) throws ObjectNotFoundException { + Set userSet = new HashSet(); + userSet.add(user); + workgroupService.createWorkgroup("Workgroup for user: " + user.getUserDetails().getUsername(), userSet, run, run.getPeriodOfStudent(user)); + } + + private void loginStudent(HttpServletRequest request, User user) { + UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user.getUserDetails().getUsername(), "null"); + Authentication auth = authenticationManager.authenticate(authReq); + SecurityContext sc = SecurityContextHolder.getContext(); + sc.setAuthentication(auth); + HttpSession session = request.getSession(true); + session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc); + } + + private User createNewStudentAccount() throws DuplicateUsernameException { + StudentUserDetails sud = new StudentUserDetails(); + sud.setFirstname("null"); + sud.setLastname("null"); + sud.setBirthday(new Date()); + sud.setPassword("null"); + sud.setGender(Gender.UNSPECIFIED); + sud.setEmailAddress("null@null.com"); + sud.setLanguage("null"); + return userService.createUser(sud); + } +} diff --git a/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java b/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java index 912381d81..e95211b12 100644 --- a/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java +++ b/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -43,6 +44,7 @@ import org.wise.portal.domain.run.Run; import org.wise.portal.domain.run.StudentRunInfo; import org.wise.portal.domain.user.User; +import org.wise.portal.domain.user.impl.UserImpl; import org.wise.portal.domain.workgroup.Workgroup; import org.wise.portal.service.group.GroupService; import org.wise.portal.service.run.RunService; From 8ff88e4dd325ebdaf0a9b7026f49453922635b0c Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 20 May 2025 15:02:47 -0700 Subject: [PATCH 02/22] Store isSurvey in RunImpl table of database (not working) --- .../java/org/wise/portal/domain/run/Run.java | 10 ++++++++++ .../wise/portal/domain/run/impl/RunImpl.java | 8 ++++++++ .../portal/domain/run/impl/RunParameters.java | 2 ++ .../survey/SurveyAPIController.java | 20 +++++++++++-------- .../teacher/TeacherAPIController.java | 3 ++- .../wise/portal/service/run/RunService.java | 2 +- .../service/run/impl/RunServiceImpl.java | 8 +++++--- 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/wise/portal/domain/run/Run.java b/src/main/java/org/wise/portal/domain/run/Run.java index 0aa552c9c..70c7c2162 100644 --- a/src/main/java/org/wise/portal/domain/run/Run.java +++ b/src/main/java/org/wise/portal/domain/run/Run.java @@ -240,6 +240,16 @@ public interface Run extends Persistable { */ boolean isIdeaManagerEnabled(); + /** + * @return Whether or not the run a survey + */ + Boolean getIsSurvey(); + + /** + * @param isSurvey + */ + void setIsSurvey(Boolean isSurvey); + /** * @return Integer maxWorkgroupSize */ diff --git a/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java b/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java index 3262db1cf..5a63fd0f9 100644 --- a/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java +++ b/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java @@ -100,6 +100,9 @@ public class RunImpl implements Run { @Transient private static final String COLUMN_NAME_EXTRAS = "extras"; + @Transient + private static final String COLUMN_NAME_IS_SURVEY = "isSurvey"; + @Transient private static final String COLUMN_NAME_MAX_WORKGROUP_SIZE = "maxWorkgroupSize"; @@ -199,6 +202,11 @@ public class RunImpl implements Run { @Setter private String info; // other info pertaining to the run + @Column(name = COLUMN_NAME_IS_SURVEY) + @Getter + @Setter + private Boolean isSurvey; + @Column(name = COLUMN_NAME_MAX_WORKGROUP_SIZE, nullable = true) @Getter @Setter diff --git a/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java b/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java index 188792166..7de5efecf 100644 --- a/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java +++ b/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java @@ -70,6 +70,8 @@ public class RunParameters implements Serializable { private Boolean isLockedAfterEndDate = false; + private Boolean isSurvey = false; + public String printAllPeriods() { String allPeriods = null; diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 0a7f5bdbf..af4ec3043 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -54,17 +54,21 @@ public class SurveyAPIController { @Autowired private WorkgroupService workgroupService; - @GetMapping("/launch/{p}") - public void launchSurveyRun(@PathVariable String p, HttpServletResponse response, HttpServletRequest request) + @GetMapping("/launch/{code}") + public void launchSurveyRun(@PathVariable String code, HttpServletResponse response, HttpServletRequest request) throws IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - Projectcode projectCode = new Projectcode(p); + Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); - User user = this.createNewStudentAccount(); - loginStudent(request, user); - studentService.addStudentToRun(user, projectCode); - createWorkgroupForUser(user, run); - response.sendRedirect("/student/unit/" + run.getId()); + if (run.getIsSurvey()) { + User user = this.createNewStudentAccount(); + loginStudent(request, user); + studentService.addStudentToRun(user, projectCode); + createWorkgroupForUser(user, run); + response.sendRedirect("/student/unit/" + run.getId()); + } else { + response.sendRedirect("/"); + } } private void createWorkgroupForUser(User user, Run run) throws ObjectNotFoundException { diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java index b715857a5..b26d1f72a 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java @@ -255,6 +255,7 @@ private List getSharedOwnerPermissionsList(Run run, User user) { @PostMapping("/run/create") HashMap createRun(Authentication auth, HttpServletRequest request, @RequestParam("projectId") Long projectId, @RequestParam("periods") String periods, + @RequestParam("isSurvey") Boolean isSurvey, @RequestParam("maxStudentsPerTeam") Integer maxStudentsPerTeam, @RequestParam("startDate") Long startDate, @RequestParam(value = "endDate", required = false) Long endDate, @@ -263,7 +264,7 @@ HashMap createRun(Authentication auth, HttpServletRequest reques User user = userService.retrieveUserByUsername(auth.getName()); Locale locale = request.getLocale(); Set periodNames = createPeriodNamesSet(periods); - Run run = runService.createRun(projectId, user, periodNames, maxStudentsPerTeam, startDate, + Run run = runService.createRun(projectId, user, periodNames, isSurvey, maxStudentsPerTeam, startDate, endDate, isLockedAfterEndDate, locale); return getRunMap(user, run); } diff --git a/src/main/java/org/wise/portal/service/run/RunService.java b/src/main/java/org/wise/portal/service/run/RunService.java index 52ad5c438..060a32bc6 100644 --- a/src/main/java/org/wise/portal/service/run/RunService.java +++ b/src/main/java/org/wise/portal/service/run/RunService.java @@ -58,7 +58,7 @@ public interface RunService { */ Run createRun(RunParameters runParameters) throws ObjectNotFoundException; - Run createRun(Long projectId, User user, Set periodNames, Integer maxStudentsPerTeam, + Run createRun(Long projectId, User user, Set periodNames, Boolean isSurvey, Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, Locale locale) throws Exception; /** diff --git a/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java b/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java index ea1f40187..1d78fc555 100644 --- a/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java +++ b/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java @@ -199,6 +199,7 @@ public Run createRun(RunParameters runParameters) { run.setStarttime(runParameters.getStartTime()); run.setRuncode(generateUniqueRunCode(runParameters.getLocale())); run.setOwner(runParameters.getOwner()); + run.setIsSurvey(runParameters.getIsSurvey()); run.setMaxWorkgroupSize(runParameters.getMaxWorkgroupSize()); run.setProject(project); run.setName("" + runParameters.getProject().getName()); @@ -239,11 +240,11 @@ public Run createRun(RunParameters runParameters) { } @Transactional() - public Run createRun(Long projectId, User user, Set periodNames, + public Run createRun(Long projectId, User user, Set periodNames, Boolean isSurvey, Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, Locale locale) throws Exception { Project project = projectService.copyProject(projectId, user); - RunParameters runParameters = createRunParameters(project, user, periodNames, + RunParameters runParameters = createRunParameters(project, user, periodNames, isSurvey, maxStudentsPerTeam, startDate, endDate, isLockedAfterEndDate, locale); Run run = createRun(runParameters); createTeacherWorkgroup(run, user); @@ -251,7 +252,7 @@ public Run createRun(Long projectId, User user, Set periodNames, return run; } - public RunParameters createRunParameters(Project project, User user, Set periodNames, + public RunParameters createRunParameters(Project project, User user, Set periodNames, Boolean isSurvey, Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, Locale locale) { RunParameters runParameters = new RunParameters(); @@ -261,6 +262,7 @@ public RunParameters createRunParameters(Project project, User user, Set runParameters.setLocale(locale); runParameters.setPostLevel(5); runParameters.setPeriodNames(periodNames); + runParameters.setIsSurvey(isSurvey); runParameters.setMaxWorkgroupSize(maxStudentsPerTeam); runParameters.setStartTime(new Date(startDate)); if (endDate == null || endDate <= startDate) { From 53baf978195652e3d27c7e15f9467f01ea184d36 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 20 May 2025 15:38:22 -0700 Subject: [PATCH 03/22] Give survey students new role to differentiate from real student accounts --- .../java/org/wise/portal/domain/user/User.java | 2 ++ .../wise/portal/domain/user/impl/UserImpl.java | 4 ++++ .../controllers/survey/SurveyAPIController.java | 16 +++++++++++++--- .../authentication/UserDetailsService.java | 2 ++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/wise/portal/domain/user/User.java b/src/main/java/org/wise/portal/domain/user/User.java index 016fd85d6..9c2de34a7 100644 --- a/src/main/java/org/wise/portal/domain/user/User.java +++ b/src/main/java/org/wise/portal/domain/user/User.java @@ -48,6 +48,8 @@ public interface User extends Persistable, Comparable { boolean isStudent(); + boolean isSurveyStudent(); + boolean isTeacher(); boolean isTrustedAuthor(); diff --git a/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java b/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java index 83a164a63..d84be1070 100644 --- a/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java +++ b/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java @@ -78,6 +78,10 @@ public boolean isStudent() { return userDetails.hasGrantedAuthority(UserDetailsService.STUDENT_ROLE); } + public boolean isSurveyStudent() { + return userDetails.hasGrantedAuthority(UserDetailsService.SURVEY_STUDENT_ROLE); + } + public boolean isTeacher() { return userDetails.hasGrantedAuthority(UserDetailsService.TEACHER_ROLE); } diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index af4ec3043..54616bc0e 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -11,7 +11,9 @@ import org.wise.portal.domain.project.impl.Projectcode; import org.wise.portal.domain.run.Run; import org.wise.portal.domain.user.User; +import org.wise.portal.service.authentication.AuthorityNotFoundException; import org.wise.portal.service.authentication.DuplicateUsernameException; +import org.wise.portal.service.authentication.UserDetailsService; import org.wise.portal.service.run.RunService; import org.wise.portal.service.student.StudentService; import org.wise.portal.service.user.UserService; @@ -48,6 +50,9 @@ public class SurveyAPIController { @Autowired private StudentService studentService; + @Autowired + private UserDetailsService userDetailsService; + @Autowired private UserService userService; @@ -56,7 +61,8 @@ public class SurveyAPIController { @GetMapping("/launch/{code}") public void launchSurveyRun(@PathVariable String code, HttpServletResponse response, HttpServletRequest request) - throws IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { + throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, + PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); @@ -86,7 +92,7 @@ private void loginStudent(HttpServletRequest request, User user) { session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc); } - private User createNewStudentAccount() throws DuplicateUsernameException { + private User createNewStudentAccount() throws AuthorityNotFoundException, DuplicateUsernameException { StudentUserDetails sud = new StudentUserDetails(); sud.setFirstname("null"); sud.setLastname("null"); @@ -95,6 +101,10 @@ private User createNewStudentAccount() throws DuplicateUsernameException { sud.setGender(Gender.UNSPECIFIED); sud.setEmailAddress("null@null.com"); sud.setLanguage("null"); - return userService.createUser(sud); + + User user = userService.createUser(sud); + user.getUserDetails().addAuthority(userDetailsService.loadAuthorityByName("ROLE_SURVEY_STUDENT")); + + return user; } } diff --git a/src/main/java/org/wise/portal/service/authentication/UserDetailsService.java b/src/main/java/org/wise/portal/service/authentication/UserDetailsService.java index 488f5141e..d303291f1 100644 --- a/src/main/java/org/wise/portal/service/authentication/UserDetailsService.java +++ b/src/main/java/org/wise/portal/service/authentication/UserDetailsService.java @@ -46,6 +46,8 @@ public interface UserDetailsService String STUDENT_ROLE = "ROLE_STUDENT"; + String SURVEY_STUDENT_ROLE = "ROLE_SURVEY_STUDENT"; + String AUTHOR_ROLE = "ROLE_AUTHOR"; String TRUSTED_AUTHOR_ROLE = "ROLE_TRUSTED_AUTHOR"; From 95c01897486d9f15a67cf2bfb1375b11b88c63f8 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 21 May 2025 08:23:35 -0700 Subject: [PATCH 04/22] Fixed isSurvey issue in database --- src/main/resources/wise_db_init.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/wise_db_init.sql b/src/main/resources/wise_db_init.sql index 829b54663..9e6a57384 100644 --- a/src/main/resources/wise_db_init.sql +++ b/src/main/resources/wise_db_init.sql @@ -330,6 +330,7 @@ create table runs ( end_time datetime, extras mediumtext, info varchar(255), + isSurvey bit, lastRun datetime, loggingLevel integer, maxWorkgroupSize integer, From e3c753f0046680ed5f96c6739d2027a309b112fe Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 21 May 2025 14:39:48 -0700 Subject: [PATCH 05/22] Finished survey student role --- src/main/java/org/wise/portal/domain/user/impl/UserImpl.java | 3 +++ .../web/controllers/survey/SurveyAPIController.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java b/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java index d84be1070..813fe67cc 100644 --- a/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java +++ b/src/main/java/org/wise/portal/domain/user/impl/UserImpl.java @@ -115,6 +115,9 @@ public List getRoles() { if (this.isStudent()) { roles.add("student"); } + if (this.isSurveyStudent()) { + roles.add("surveyStudent"); + } return roles; } diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 54616bc0e..4032913a7 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -103,7 +103,7 @@ private User createNewStudentAccount() throws AuthorityNotFoundException, Duplic sud.setLanguage("null"); User user = userService.createUser(sud); - user.getUserDetails().addAuthority(userDetailsService.loadAuthorityByName("ROLE_SURVEY_STUDENT")); + user.getUserDetails().addAuthority(userDetailsService.loadAuthorityByName(UserDetailsService.SURVEY_STUDENT_ROLE)); return user; } From 4d2bd2d4da6a6dfafec4105d6f4e617c37ee8a65 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 21 May 2025 15:36:54 -0700 Subject: [PATCH 06/22] Send isSurvey data back to the client with the rest of the run data --- .../presentation/web/controllers/user/UserAPIController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java index ddf66aab1..2a463b113 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java @@ -305,6 +305,7 @@ protected HashMap getRunMap(User user, Run run) { HashMap map = new HashMap(); map.put("id", run.getId()); map.put("name", run.getName()); + map.put("isSurvey", run.getIsSurvey()); map.put("maxStudentsPerTeam", run.getMaxWorkgroupSize()); map.put("runCode", run.getRuncode()); map.put("startTime", run.getStartTimeMilliseconds()); From 228339e94c966f1aff11ab07ea61aa79ac4c4cf0 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Thu, 22 May 2025 20:20:01 -0700 Subject: [PATCH 07/22] Hard limit on number of workgroups for survey units --- .../survey/SurveyAPIController.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 4032913a7..6ddf7020e 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -67,16 +67,24 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { - User user = this.createNewStudentAccount(); - loginStudent(request, user); - studentService.addStudentToRun(user, projectCode); - createWorkgroupForUser(user, run); - response.sendRedirect("/student/unit/" + run.getId()); + if (underWorkgroupLimit(run)) { + User user = this.createNewStudentAccount(); + loginStudent(request, user); + studentService.addStudentToRun(user, projectCode); + createWorkgroupForUser(user, run); + response.sendRedirect("/student/unit/" + run.getId()); + } else { + response.sendRedirect("/workgroupLimitReached"); + } } else { response.sendRedirect("/"); } } + private Boolean underWorkgroupLimit(Run run) { + return workgroupService.getWorkgroupsForRun(run).size() <= 1000; + } + private void createWorkgroupForUser(User user, Run run) throws ObjectNotFoundException { Set userSet = new HashSet(); userSet.add(user); From 7813e725ff03c506f975db7d5bf8609fc592fb6c Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 27 May 2025 14:09:38 -0700 Subject: [PATCH 08/22] Redirect to log out page if logged in --- .../web/controllers/survey/SurveyAPIController.java | 12 +++++++----- .../web/controllers/user/UserAPIController.java | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 6ddf7020e..9e0658cda 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -64,17 +64,19 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - Projectcode projectCode = new Projectcode(code); + Projectcode projectCode = new Projectcode(code.replaceAll("++", " ")); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { - if (underWorkgroupLimit(run)) { + if (!SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")) { // Already signed in + response.sendRedirect("/survey/logout"); + } else if (underWorkgroupLimit(run)) { User user = this.createNewStudentAccount(); loginStudent(request, user); studentService.addStudentToRun(user, projectCode); createWorkgroupForUser(user, run); response.sendRedirect("/student/unit/" + run.getId()); } else { - response.sendRedirect("/workgroupLimitReached"); + response.sendRedirect("/survey/workgroupLimitReached"); } } else { response.sendRedirect("/"); @@ -102,8 +104,8 @@ private void loginStudent(HttpServletRequest request, User user) { private User createNewStudentAccount() throws AuthorityNotFoundException, DuplicateUsernameException { StudentUserDetails sud = new StudentUserDetails(); - sud.setFirstname("null"); - sud.setLastname("null"); + sud.setFirstname("survey_student"); + sud.setLastname(Integer.toString((int) Math.ceil(Math.random() * 10000))); sud.setBirthday(new Date()); sud.setPassword("null"); sud.setGender(Gender.UNSPECIFIED); diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java index 2a463b113..cd0e82eec 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java @@ -256,6 +256,7 @@ protected HashMap getRunInfo(Run run) { info.put("teacherFirstName", owner.getUserDetails().getFirstname()); info.put("teacherLastName", owner.getUserDetails().getLastname()); info.put("wiseVersion", run.getProject().getWiseVersion()); + info.put("isSurvey", run.getIsSurvey()); return info; } From c6c18ef8cdae86d836875e7f1f18fd56dc63a357 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 27 May 2025 15:46:02 -0700 Subject: [PATCH 09/22] Don't create two workgroups per student --- .../web/controllers/survey/SurveyAPIController.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 9e0658cda..47cfd1d5e 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -64,7 +64,7 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - Projectcode projectCode = new Projectcode(code.replaceAll("++", " ")); + Projectcode projectCode = new Projectcode(code.replaceAll("\\+\\+", " ")); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { if (!SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")) { // Already signed in @@ -73,7 +73,6 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo User user = this.createNewStudentAccount(); loginStudent(request, user); studentService.addStudentToRun(user, projectCode); - createWorkgroupForUser(user, run); response.sendRedirect("/student/unit/" + run.getId()); } else { response.sendRedirect("/survey/workgroupLimitReached"); @@ -87,12 +86,6 @@ private Boolean underWorkgroupLimit(Run run) { return workgroupService.getWorkgroupsForRun(run).size() <= 1000; } - private void createWorkgroupForUser(User user, Run run) throws ObjectNotFoundException { - Set userSet = new HashSet(); - userSet.add(user); - workgroupService.createWorkgroup("Workgroup for user: " + user.getUserDetails().getUsername(), userSet, run, run.getPeriodOfStudent(user)); - } - private void loginStudent(HttpServletRequest request, User user) { UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user.getUserDetails().getUsername(), "null"); Authentication auth = authenticationManager.authenticate(authReq); From e6d358c688555593c73a8a939bbc3c3b03a386ee Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 27 May 2025 17:36:42 -0700 Subject: [PATCH 10/22] Clean code --- .../survey/SurveyAPIController.java | 20 +++++++++++++------ .../student/impl/StudentServiceImpl.java | 2 -- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 47cfd1d5e..db0d198a1 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -21,8 +21,6 @@ import java.io.IOException; import java.util.Date; -import java.util.HashSet; -import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -67,7 +65,16 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo Projectcode projectCode = new Projectcode(code.replaceAll("\\+\\+", " ")); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { - if (!SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")) { // Already signed in + handleSurveyLaunched(response, request, run, projectCode); + } else { + response.sendRedirect("/"); + } + } + + private void handleSurveyLaunched(HttpServletResponse response, HttpServletRequest request, Run run, Projectcode projectCode) + throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, + PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { + if (userAlreadySignedIn()) { response.sendRedirect("/survey/logout"); } else if (underWorkgroupLimit(run)) { User user = this.createNewStudentAccount(); @@ -77,9 +84,10 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo } else { response.sendRedirect("/survey/workgroupLimitReached"); } - } else { - response.sendRedirect("/"); - } + } + + private Boolean userAlreadySignedIn() { + return !SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser"); } private Boolean underWorkgroupLimit(Run run) { diff --git a/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java b/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java index e95211b12..912381d81 100644 --- a/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java +++ b/src/main/java/org/wise/portal/service/student/impl/StudentServiceImpl.java @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -44,7 +43,6 @@ import org.wise.portal.domain.run.Run; import org.wise.portal.domain.run.StudentRunInfo; import org.wise.portal.domain.user.User; -import org.wise.portal.domain.user.impl.UserImpl; import org.wise.portal.domain.workgroup.Workgroup; import org.wise.portal.service.group.GroupService; import org.wise.portal.service.run.RunService; From d43a28dbde188604879f8d4cce52763c608b737b Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Thu, 29 May 2025 13:06:06 -0700 Subject: [PATCH 11/22] Working on tests --- .../survey/SurveyAPIController.java | 20 +-- .../survey/SurveyAPIControllerTest.java | 127 ++++++++++++++++++ .../teacher/TeacherAPIControllerTest.java | 4 +- 3 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index db0d198a1..f0c04bcb0 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -66,7 +66,7 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { handleSurveyLaunched(response, request, run, projectCode); - } else { + } else { response.sendRedirect("/"); } } @@ -75,15 +75,15 @@ private void handleSurveyLaunched(HttpServletResponse response, HttpServletReque throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { if (userAlreadySignedIn()) { - response.sendRedirect("/survey/logout"); - } else if (underWorkgroupLimit(run)) { - User user = this.createNewStudentAccount(); - loginStudent(request, user); - studentService.addStudentToRun(user, projectCode); - response.sendRedirect("/student/unit/" + run.getId()); - } else { - response.sendRedirect("/survey/workgroupLimitReached"); - } + response.sendRedirect("/survey/logout"); + } else if (underWorkgroupLimit(run)) { + User user = this.createNewStudentAccount(); + loginStudent(request, user); + studentService.addStudentToRun(user, projectCode); + response.sendRedirect("/student/unit/" + run.getId()); + } else { + response.sendRedirect("/survey/workgroupLimitReached"); + } } private Boolean userAlreadySignedIn() { diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java new file mode 100644 index 000000000..e8f24b686 --- /dev/null +++ b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java @@ -0,0 +1,127 @@ +package org.wise.portal.presentation.web.controllers.survey; + +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.easymock.EasyMockExtension; +import org.easymock.Mock; +import org.easymock.TestSubject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.wise.portal.domain.run.Run; +import org.wise.portal.domain.run.impl.RunImpl; +import org.wise.portal.domain.workgroup.Workgroup; +import org.wise.portal.domain.workgroup.impl.WorkgroupImpl; +import org.wise.portal.service.run.RunService; +import org.wise.portal.service.workgroup.WorkgroupService; + +@ExtendWith(EasyMockExtension.class) +public class SurveyAPIControllerTest { + private Run run; + private TestingAuthenticationToken authority; + private SecurityContext securityContext; + + @TestSubject SurveyAPIController surveyAPIController = new SurveyAPIController(); + + @Mock HttpServletResponse httpServletResponse; + + @Mock HttpServletRequest httpServletRequest; + + @Mock RunService runService; + + @Mock WorkgroupService workgroupService; + + @BeforeEach + public void setUp() { + run = new RunImpl(); + run.setId(1); + } + + SecurityContext getSecurityContext(String role, String authorityName) { + authority = new TestingAuthenticationToken(role, + new GrantedAuthority[] { new SimpleGrantedAuthority(authorityName) }); + authority.setAuthenticated(true); + securityContext = new SecurityContextImpl(); + securityContext.setAuthentication(authority); + } + + @Test + public void launchSurveyRun_NotASurvey_RedirectHomePage() throws Exception { + httpServletResponse.sendRedirect("/"); + expectLastCall(); + replay(httpServletResponse); + run.setIsSurvey(false); + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + } + + @Test + public void launchSurveyRun_AlreadySignedIn_RedirectLogOutPage() throws Exception { + httpServletResponse.sendRedirect("/survey/logout"); + expectLastCall(); + replay(httpServletResponse); + run.setIsSurvey(true); + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + SecurityContextHolder.setContext(getSecurityContext("student", "ROLE_STUDENT")); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + } + + @Test + public void launchSurveyRun_OverWorkgroupLimit_RedirectWorkgroupLimitPage() throws Exception { + httpServletResponse.sendRedirect("/survey/workgroupLimitReached"); + expectLastCall(); + replay(httpServletResponse); + run.setIsSurvey(false); + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + SecurityContextHolder.setContext(getSecurityContext("anonymousUser", "ROLE_ANONYMOUS")); + List workgroups = new ArrayList(); + for (int i = 0; i < 1005; i++) { + workgroups.add(new WorkgroupImpl()); + } + expect(workgroupService.getWorkgroupsForRun(run)).andReturn(workgroups); + replay(workgroupService); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + verify(workgroupService); + } + + @Test + public void launchSurveyRun_NoIssues_RedirectUnit() throws Exception { + httpServletResponse.sendRedirect("/student/unit/1"); + expectLastCall(); + replay(httpServletResponse); + run.setIsSurvey(false); + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + SecurityContextHolder.setContext(getSecurityContext("anonymousUser", "ROLE_ANONYMOUS")); + expect(workgroupService.getWorkgroupsForRun(run)).andReturn(new ArrayList()); + replay(workgroupService); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + verify(workgroupService); + } +} + diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIControllerTest.java index 0f421c595..d07076070 100644 --- a/src/test/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIControllerTest.java +++ b/src/test/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIControllerTest.java @@ -364,10 +364,10 @@ public void createRun_ThreePeriods_CreateRun() throws Exception { periodNamesSet.add("1"); periodNamesSet.add("2"); periodNamesSet.add("free"); - expect(runService.createRun(projectId, teacher1, periodNamesSet, maxStudentsPerTeam, startDate, + expect(runService.createRun(projectId, teacher1, periodNamesSet, false, maxStudentsPerTeam, startDate, endDate, isLockedAfterEndDate, Locale.US)).andReturn(run1); replay(runService); - teacherAPIController.createRun(teacherAuth, request, projectId, periods, maxStudentsPerTeam, + teacherAPIController.createRun(teacherAuth, request, projectId, periods, false, maxStudentsPerTeam, startDate, endDate, isLockedAfterEndDate); verify(userService); verify(request); From 085d1f56db0494a86844d6be9164e6103ce73618 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Thu, 29 May 2025 13:17:15 -0700 Subject: [PATCH 12/22] Fix compile issues --- .../survey/SurveyAPIControllerTest.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java index e8f24b686..aef2004db 100644 --- a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java +++ b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java @@ -22,6 +22,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; import org.wise.portal.domain.run.Run; import org.wise.portal.domain.run.impl.RunImpl; import org.wise.portal.domain.workgroup.Workgroup; @@ -35,20 +36,25 @@ public class SurveyAPIControllerTest { private TestingAuthenticationToken authority; private SecurityContext securityContext; - @TestSubject SurveyAPIController surveyAPIController = new SurveyAPIController(); + @TestSubject + SurveyAPIController surveyAPIController = new SurveyAPIController(); - @Mock HttpServletResponse httpServletResponse; - - @Mock HttpServletRequest httpServletRequest; + @Mock + HttpServletResponse httpServletResponse; - @Mock RunService runService; + @Mock + HttpServletRequest httpServletRequest; - @Mock WorkgroupService workgroupService; + @Mock + RunService runService; + + @Mock + WorkgroupService workgroupService; @BeforeEach public void setUp() { run = new RunImpl(); - run.setId(1); + run.setId(1L); } SecurityContext getSecurityContext(String role, String authorityName) { @@ -57,6 +63,7 @@ SecurityContext getSecurityContext(String role, String authorityName) { authority.setAuthenticated(true); securityContext = new SecurityContextImpl(); securityContext.setAuthentication(authority); + return securityContext; } @Test @@ -124,4 +131,3 @@ public void launchSurveyRun_NoIssues_RedirectUnit() throws Exception { verify(workgroupService); } } - From a729c91818e92e50628fa023b43bb54c93d0ca1a Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Thu, 29 May 2025 14:04:14 -0700 Subject: [PATCH 13/22] Simplify path to launch survey to /run-survey/code --- .../survey/SurveyAPIController.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index f0c04bcb0..10e8282de 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -37,7 +37,7 @@ import org.springframework.web.bind.annotation.PathVariable; @RestController -@RequestMapping("/api/survey") +@RequestMapping("/run-survey") public class SurveyAPIController { @Autowired private AuthenticationManager authenticationManager; @@ -57,10 +57,11 @@ public class SurveyAPIController { @Autowired private WorkgroupService workgroupService; - @GetMapping("/launch/{code}") - public void launchSurveyRun(@PathVariable String code, HttpServletResponse response, HttpServletRequest request) - throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, - PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { + @GetMapping("/{code}") + public void launchSurveyRun(@PathVariable String code, HttpServletResponse response, + HttpServletRequest request) throws AuthorityNotFoundException, IOException, + DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, + StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { Projectcode projectCode = new Projectcode(code.replaceAll("\\+\\+", " ")); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); @@ -71,9 +72,10 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo } } - private void handleSurveyLaunched(HttpServletResponse response, HttpServletRequest request, Run run, Projectcode projectCode) - throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, - PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { + private void handleSurveyLaunched(HttpServletResponse response, HttpServletRequest request, + Run run, Projectcode projectCode) throws AuthorityNotFoundException, IOException, + DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, + StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { if (userAlreadySignedIn()) { response.sendRedirect("/survey/logout"); } else if (underWorkgroupLimit(run)) { @@ -87,7 +89,8 @@ private void handleSurveyLaunched(HttpServletResponse response, HttpServletReque } private Boolean userAlreadySignedIn() { - return !SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser"); + return !SecurityContextHolder.getContext().getAuthentication().getPrincipal() + .equals("anonymousUser"); } private Boolean underWorkgroupLimit(Run run) { @@ -95,15 +98,17 @@ private Boolean underWorkgroupLimit(Run run) { } private void loginStudent(HttpServletRequest request, User user) { - UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user.getUserDetails().getUsername(), "null"); + UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken( + user.getUserDetails().getUsername(), "null"); Authentication auth = authenticationManager.authenticate(authReq); SecurityContext sc = SecurityContextHolder.getContext(); sc.setAuthentication(auth); HttpSession session = request.getSession(true); session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc); } - - private User createNewStudentAccount() throws AuthorityNotFoundException, DuplicateUsernameException { + + private User createNewStudentAccount() + throws AuthorityNotFoundException, DuplicateUsernameException { StudentUserDetails sud = new StudentUserDetails(); sud.setFirstname("survey_student"); sud.setLastname(Integer.toString((int) Math.ceil(Math.random() * 10000))); @@ -114,7 +119,8 @@ private User createNewStudentAccount() throws AuthorityNotFoundException, Duplic sud.setLanguage("null"); User user = userService.createUser(sud); - user.getUserDetails().addAuthority(userDetailsService.loadAuthorityByName(UserDetailsService.SURVEY_STUDENT_ROLE)); + user.getUserDetails().addAuthority( + userDetailsService.loadAuthorityByName(UserDetailsService.SURVEY_STUDENT_ROLE)); return user; } From 4ffa4970b910fd12581ee2cce123d90374bfe293 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Thu, 29 May 2025 14:04:35 -0700 Subject: [PATCH 14/22] Add ROLE_SURVEY_STUDENT initial value --- src/main/resources/wise_db_init.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/wise_db_init.sql b/src/main/resources/wise_db_init.sql index 9e6a57384..7e795f752 100644 --- a/src/main/resources/wise_db_init.sql +++ b/src/main/resources/wise_db_init.sql @@ -564,7 +564,7 @@ CREATE TABLE `acl_object_identity_to_user_tags` ( -- initial data for wise below -INSERT INTO granted_authorities VALUES (1,'ROLE_USER',0),(2,'ROLE_ADMINISTRATOR',0),(3,'ROLE_TEACHER',0),(4,'ROLE_STUDENT',0),(5,'ROLE_AUTHOR',0),(6,'ROLE_RESEARCHER',0),(7,'ROLE_TRUSTED_AUTHOR',0),(8,'ROLE_TRANSLATOR',0); +INSERT INTO granted_authorities VALUES (1,'ROLE_USER',0),(2,'ROLE_ADMINISTRATOR',0),(3,'ROLE_TEACHER',0),(4,'ROLE_STUDENT',0),(5,'ROLE_AUTHOR',0),(6,'ROLE_RESEARCHER',0),(7,'ROLE_TRUSTED_AUTHOR',0),(8,'ROLE_TRANSLATOR',0),(9, 'ROLE_SURVEY_STUDENT'); INSERT INTO portal (id,portalname,settings,announcement,projectLibraryGroups,projectMetadataSettings,run_survey_template,sendmail_on_exception,OPTLOCK) VALUES (1,'My Production WISE Site (change me)','{isLoginAllowed:true}','{"visible":false,"bannerText":"","bannerButton":"","title":"","content":"","buttons":[]}','[]','{"fields":[{"name":"Title","key":"title","type":"input"},{"name":"Summary","key":"summary","type":"textarea"},{"name":"Language","key":"language","type":"radio","choices":["English","Chinese (Simplified)","Chinese (Traditional)","Dutch","German","Greek","Hebrew","Japanese","Korean","Portuguese","Spanish","Thai","Turkish"]},{"name":"Subject","key":"subject","type":"radio","choices":["Life Science","Physical Science","Earth Science","General Science","Biology","Chemistry","Physics","Other"]},{"name":"Time Required to Complete Project","key":"time","type":"input"},{"name":"Supported Devices","key":"supportedDevices","type":"checkbox","choices":["PC","Tablet"]}],"i18n":{"lifeScience":{"en":"Life Science","ja":"ライフサイエンス"},"earthScience":{"en":"Earth Science","ja":"地球科学"},"physicalScience":{"en":"Physical Science","ja":"物理科学","es":"ciencia física"}}}','{"save_time":null,"items":[{"id":"recommendProjectToOtherTeachers","type":"radio","prompt":"How likely would you recommend this project to other teachers?","choices":[{"id":"5","text":"Extremely likely"},{"id":"4","text":"Very likely"},{"id":"3","text":"Moderately likely"},{"id":"2","text":"Slightly likely"},{"id":"1","text":"Not at all likely"}],"answer":null},{"id":"runProjectAgain","type":"radio","prompt":"How likely would you run this project again?","choices":[{"id":"5","text":"Extremely likely"},{"id":"4","text":"Very likely"},{"id":"3","text":"Moderately likely"},{"id":"2","text":"Slightly likely"},{"id":"1","text":"Not at all likely"}],"answer":null},{"id":"useWISEAgain","type":"radio","prompt":"How likely would you use WISE again in your classroom?","choices":[{"id":"5","text":"Extremely likely"},{"id":"4","text":"Very likely"},{"id":"3","text":"Moderately likely"},{"id":"2","text":"Slightly likely"},{"id":"1","text":"Not at all likely"}],"answer":null},{"id":"adviceForOtherTeachers","type":"textarea","prompt":"Please share any advice for other teachers about this project or about WISE in general.","answer":null},{"id":"technicalProblems","type":"textarea","prompt":"Please write about any technical problems that you had while running this project.","answer":null},{"id":"generalFeedback","type":"textarea","prompt":"Please provide any other feedback to WISE staff.","answer":null}]}',1,0); From 6a3dcbee24970c5de43b58d64cacb5ebd6bb3a19 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Thu, 29 May 2025 14:28:40 -0700 Subject: [PATCH 15/22] Add isSurvey flag --- .../presentation/web/controllers/run/RunInfoAPIController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java index bf6993fda..30ed8555f 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java @@ -62,6 +62,7 @@ private HashMap getRunInfo(Run run) { info.put("teacherFirstName", owner.getUserDetails().getFirstname()); info.put("teacherLastName", owner.getUserDetails().getLastname()); info.put("wiseVersion", run.getProject().getWiseVersion()); + info.put("isSurvey", run.getIsSurvey()); return info; } From 39c78b4c4718c1fbb282e1261d02ee78de4cfa1f Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Fri, 30 May 2025 14:29:55 -0700 Subject: [PATCH 16/22] Log out logged in users automatically + allow survey students already in run to get back into run --- .../survey/SurveyAPIController.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 10e8282de..60220d1c7 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -68,7 +68,7 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo if (run.getIsSurvey()) { handleSurveyLaunched(response, request, run, projectCode); } else { - response.sendRedirect("/"); + sendRedirect(response, "/"); } } @@ -76,21 +76,35 @@ private void handleSurveyLaunched(HttpServletResponse response, HttpServletReque Run run, Projectcode projectCode) throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - if (userAlreadySignedIn()) { - response.sendRedirect("/survey/logout"); - } else if (underWorkgroupLimit(run)) { + + Object principal = getSecurityContextHolderPrincipal(); + if (principal instanceof StudentUserDetails + && isStudentAssociatedWithRun(run, (StudentUserDetails) principal)) { + sendRedirect(response, "/student/unit/" + run.getId()); + return; + } else { + SecurityContextHolder.getContext().setAuthentication(null); + } + if (underWorkgroupLimit(run)) { User user = this.createNewStudentAccount(); loginStudent(request, user); studentService.addStudentToRun(user, projectCode); - response.sendRedirect("/student/unit/" + run.getId()); + sendRedirect(response, "/student/unit/" + run.getId()); } else { - response.sendRedirect("/survey/workgroupLimitReached"); + sendRedirect(response, "/survey/workgroupLimitReached"); } } - private Boolean userAlreadySignedIn() { - return !SecurityContextHolder.getContext().getAuthentication().getPrincipal() - .equals("anonymousUser"); + private void sendRedirect(HttpServletResponse response, String redirectUrl) throws IOException { + response.sendRedirect(redirectUrl); + } + + private Object getSecurityContextHolderPrincipal() { + return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + private Boolean isStudentAssociatedWithRun(Run run, StudentUserDetails principal) { + return run.isStudentAssociatedToThisRun(userService.retrieveStudentById((principal).getId())); } private Boolean underWorkgroupLimit(Run run) { From 1a73072dadbf277abeb72ac1861816397c9a4cc6 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Fri, 30 May 2025 14:53:46 -0700 Subject: [PATCH 17/22] Don't allow custom periods for surveys --- .../web/controllers/survey/SurveyAPIController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 60220d1c7..518138a8e 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -63,7 +63,7 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - Projectcode projectCode = new Projectcode(code.replaceAll("\\+\\+", " ")); + Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); if (run.getIsSurvey()) { handleSurveyLaunched(response, request, run, projectCode); From 367fc9cc6f7a892392996761876ab8733016651c Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Mon, 2 Jun 2025 13:50:17 -0700 Subject: [PATCH 18/22] Change isSurvey from Boolean to boolean. Requires db changes: update runs set isSurvey=false where isSurvey is null; alter table runs add column isSurvey bit(1) not null default 0; --- .../java/org/wise/portal/domain/run/Run.java | 28 +++++++++---------- .../wise/portal/domain/run/impl/RunImpl.java | 14 +++++++--- .../portal/domain/run/impl/RunParameters.java | 3 +- .../controllers/run/RunInfoAPIController.java | 2 +- .../survey/SurveyAPIController.java | 6 ++-- .../teacher/TeacherAPIController.java | 6 ++-- .../controllers/user/UserAPIController.java | 2 +- .../wise/portal/service/run/RunService.java | 5 ++-- .../service/run/impl/RunServiceImpl.java | 12 ++++---- src/main/resources/wise_db_init.sql | 2 +- 10 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/wise/portal/domain/run/Run.java b/src/main/java/org/wise/portal/domain/run/Run.java index 70c7c2162..09bf4822b 100644 --- a/src/main/java/org/wise/portal/domain/run/Run.java +++ b/src/main/java/org/wise/portal/domain/run/Run.java @@ -120,7 +120,7 @@ public interface Run extends Persistable { /** * Returns the period with periodName that is associated with this run - * + * * @param periodName * @return Group the period with the periodName that is associated with this run * @throws PeriodNotFoundException @@ -214,41 +214,41 @@ public interface Run extends Persistable { /** * Sets whether or not student asset uploading is enabled for this run. - * + * * @return */ void setStudentAssetUploaderEnabled(boolean isStudentAssetUploaderEnabled); /** * Returns whether or not student asset uploading is enabled for this run. - * + * * @return */ boolean isStudentAssetUploaderEnabled(); /** * Sets whether or not idea manager is enabled for this run. - * + * * @return */ void setIdeaManagerEnabled(boolean isIdeaManagerEnabled); /** * Returns whether or not idea manager is enabled for this run. - * + * * @return */ boolean isIdeaManagerEnabled(); /** - * @return Whether or not the run a survey + * @return Whether or not the run a survey */ - Boolean getIsSurvey(); + boolean isSurvey(); /** - * @param isSurvey + * @param isSurvey */ - void setIsSurvey(Boolean isSurvey); + void setIsSurvey(boolean isSurvey); /** * @return Integer maxWorkgroupSize @@ -351,7 +351,7 @@ public interface Run extends Persistable { /** * sets student attendance for this run - * + * * @param studentAttendance */ void setStudentAttendance(List studentAttendance); @@ -363,14 +363,14 @@ public interface Run extends Persistable { /** * Gets private notes for this run - * + * * @return String private notes for this run */ String getPrivateNotes(); /** * Sets private notes for this run - * + * * @param privateNotes * private notes for this run */ @@ -378,14 +378,14 @@ public interface Run extends Persistable { /** * Gets survey for this run - * + * * @return String survey for this run */ String getSurvey(); /** * Sets survey for this run - * + * * @return String survey for this run */ void setSurvey(String survey); diff --git a/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java b/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java index 5a63fd0f9..5300ac46e 100644 --- a/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java +++ b/src/main/java/org/wise/portal/domain/run/impl/RunImpl.java @@ -203,9 +203,7 @@ public class RunImpl implements Run { private String info; // other info pertaining to the run @Column(name = COLUMN_NAME_IS_SURVEY) - @Getter - @Setter - private Boolean isSurvey; + private boolean isSurvey; @Column(name = COLUMN_NAME_MAX_WORKGROUP_SIZE, nullable = true) @Getter @@ -435,7 +433,7 @@ public static class UserAlphabeticalComparator implements Comparator { /** * Compares the user names of two User objects - * + * * @param user1 * a user object * @param user2 @@ -488,4 +486,12 @@ public boolean isLockedAfterEndDate() { public void setLockedAfterEndDate(boolean isLockedAfterEndDate) { this.isLockedAfterEndDate = isLockedAfterEndDate; } + + public boolean isSurvey() { + return isSurvey; + } + + public void setIsSurvey(boolean isSurvey) { + this.isSurvey = isSurvey; + } } diff --git a/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java b/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java index 7de5efecf..dec931f3e 100644 --- a/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java +++ b/src/main/java/org/wise/portal/domain/run/impl/RunParameters.java @@ -30,7 +30,6 @@ import org.wise.portal.domain.project.Project; import org.wise.portal.domain.user.User; -import java.io.Serializable; import java.util.*; /** @@ -70,7 +69,7 @@ public class RunParameters implements Serializable { private Boolean isLockedAfterEndDate = false; - private Boolean isSurvey = false; + private boolean isSurvey = false; public String printAllPeriods() { String allPeriods = null; diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java index 30ed8555f..061c36f08 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/run/RunInfoAPIController.java @@ -62,7 +62,7 @@ private HashMap getRunInfo(Run run) { info.put("teacherFirstName", owner.getUserDetails().getFirstname()); info.put("teacherLastName", owner.getUserDetails().getLastname()); info.put("wiseVersion", run.getProject().getWiseVersion()); - info.put("isSurvey", run.getIsSurvey()); + info.put("isSurvey", run.isSurvey()); return info; } diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 518138a8e..7ec850b44 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -65,7 +65,7 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); - if (run.getIsSurvey()) { + if (run.isSurvey()) { handleSurveyLaunched(response, request, run, projectCode); } else { sendRedirect(response, "/"); @@ -76,9 +76,9 @@ private void handleSurveyLaunched(HttpServletResponse response, HttpServletReque Run run, Projectcode projectCode) throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - + Object principal = getSecurityContextHolderPrincipal(); - if (principal instanceof StudentUserDetails + if (principal instanceof StudentUserDetails && isStudentAssociatedWithRun(run, (StudentUserDetails) principal)) { sendRedirect(response, "/student/unit/" + run.getId()); return; diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java index b26d1f72a..559ba9040 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/teacher/TeacherAPIController.java @@ -255,7 +255,7 @@ private List getSharedOwnerPermissionsList(Run run, User user) { @PostMapping("/run/create") HashMap createRun(Authentication auth, HttpServletRequest request, @RequestParam("projectId") Long projectId, @RequestParam("periods") String periods, - @RequestParam("isSurvey") Boolean isSurvey, + @RequestParam boolean isSurvey, @RequestParam("maxStudentsPerTeam") Integer maxStudentsPerTeam, @RequestParam("startDate") Long startDate, @RequestParam(value = "endDate", required = false) Long endDate, @@ -264,8 +264,8 @@ HashMap createRun(Authentication auth, HttpServletRequest reques User user = userService.retrieveUserByUsername(auth.getName()); Locale locale = request.getLocale(); Set periodNames = createPeriodNamesSet(periods); - Run run = runService.createRun(projectId, user, periodNames, isSurvey, maxStudentsPerTeam, startDate, - endDate, isLockedAfterEndDate, locale); + Run run = runService.createRun(projectId, user, periodNames, isSurvey, maxStudentsPerTeam, + startDate, endDate, isLockedAfterEndDate, locale); return getRunMap(user, run); } diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java index 5cede2dd6..ca965b81f 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/user/UserAPIController.java @@ -261,7 +261,7 @@ protected HashMap getRunMap(User user, Run run) { HashMap map = new HashMap(); map.put("id", run.getId()); map.put("name", run.getName()); - map.put("isSurvey", run.getIsSurvey()); + map.put("isSurvey", run.isSurvey()); map.put("maxStudentsPerTeam", run.getMaxWorkgroupSize()); map.put("runCode", run.getRuncode()); map.put("startTime", run.getStartTimeMilliseconds()); diff --git a/src/main/java/org/wise/portal/service/run/RunService.java b/src/main/java/org/wise/portal/service/run/RunService.java index 060a32bc6..e16c73998 100644 --- a/src/main/java/org/wise/portal/service/run/RunService.java +++ b/src/main/java/org/wise/portal/service/run/RunService.java @@ -58,8 +58,9 @@ public interface RunService { */ Run createRun(RunParameters runParameters) throws ObjectNotFoundException; - Run createRun(Long projectId, User user, Set periodNames, Boolean isSurvey, Integer maxStudentsPerTeam, - Long startDate, Long endDate, Boolean isLockedAfterEndDate, Locale locale) throws Exception; + Run createRun(Long projectId, User user, Set periodNames, boolean isSurvey, + Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, + Locale locale) throws Exception; /** * Ends this run. The side effect is that the run's endtime gets set. A Run that has ended is no diff --git a/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java b/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java index 1d78fc555..0a7b47392 100644 --- a/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java +++ b/src/main/java/org/wise/portal/service/run/impl/RunServiceImpl.java @@ -199,7 +199,7 @@ public Run createRun(RunParameters runParameters) { run.setStarttime(runParameters.getStartTime()); run.setRuncode(generateUniqueRunCode(runParameters.getLocale())); run.setOwner(runParameters.getOwner()); - run.setIsSurvey(runParameters.getIsSurvey()); + run.setIsSurvey(runParameters.isSurvey()); run.setMaxWorkgroupSize(runParameters.getMaxWorkgroupSize()); run.setProject(project); run.setName("" + runParameters.getProject().getName()); @@ -240,7 +240,7 @@ public Run createRun(RunParameters runParameters) { } @Transactional() - public Run createRun(Long projectId, User user, Set periodNames, Boolean isSurvey, + public Run createRun(Long projectId, User user, Set periodNames, boolean isSurvey, Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, Locale locale) throws Exception { Project project = projectService.copyProject(projectId, user); @@ -252,9 +252,9 @@ public Run createRun(Long projectId, User user, Set periodNames, Boolean return run; } - public RunParameters createRunParameters(Project project, User user, Set periodNames, Boolean isSurvey, - Integer maxStudentsPerTeam, Long startDate, Long endDate, Boolean isLockedAfterEndDate, - Locale locale) { + public RunParameters createRunParameters(Project project, User user, Set periodNames, + boolean isSurvey, Integer maxStudentsPerTeam, Long startDate, Long endDate, + Boolean isLockedAfterEndDate, Locale locale) { RunParameters runParameters = new RunParameters(); runParameters.setOwner(user); runParameters.setName(project.getName()); @@ -262,7 +262,7 @@ public RunParameters createRunParameters(Project project, User user, Set runParameters.setLocale(locale); runParameters.setPostLevel(5); runParameters.setPeriodNames(periodNames); - runParameters.setIsSurvey(isSurvey); + runParameters.setSurvey(isSurvey); runParameters.setMaxWorkgroupSize(maxStudentsPerTeam); runParameters.setStartTime(new Date(startDate)); if (endDate == null || endDate <= startDate) { diff --git a/src/main/resources/wise_db_init.sql b/src/main/resources/wise_db_init.sql index 7e795f752..c3339e802 100644 --- a/src/main/resources/wise_db_init.sql +++ b/src/main/resources/wise_db_init.sql @@ -330,7 +330,7 @@ create table runs ( end_time datetime, extras mediumtext, info varchar(255), - isSurvey bit, + isSurvey bit not null default 0, lastRun datetime, loggingLevel integer, maxWorkgroupSize integer, From b9ef21895110375f053b31463d2cf9411b566f76 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Mon, 2 Jun 2025 16:12:45 -0700 Subject: [PATCH 19/22] Fixed tests --- .../survey/SurveyAPIController.java | 1 - .../survey/SurveyAPIControllerTest.java | 85 +++++++++++++++---- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 7ec850b44..3a33e2b27 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -135,7 +135,6 @@ private User createNewStudentAccount() User user = userService.createUser(sud); user.getUserDetails().addAuthority( userDetailsService.loadAuthorityByName(UserDetailsService.SURVEY_STUDENT_ROLE)); - return user; } } diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java index aef2004db..3750b134d 100644 --- a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java +++ b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java @@ -2,13 +2,17 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.isA; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import javax.servlet.http.HttpServletRequest; import org.easymock.EasyMockExtension; @@ -19,15 +23,25 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; +import org.wise.portal.domain.authentication.impl.StudentUserDetails; +import org.wise.portal.domain.group.Group; +import org.wise.portal.domain.group.impl.PersistentGroup; +import org.wise.portal.domain.project.impl.Projectcode; import org.wise.portal.domain.run.Run; import org.wise.portal.domain.run.impl.RunImpl; +import org.wise.portal.domain.user.User; +import org.wise.portal.domain.user.impl.UserImpl; import org.wise.portal.domain.workgroup.Workgroup; import org.wise.portal.domain.workgroup.impl.WorkgroupImpl; +import org.wise.portal.service.authentication.UserDetailsService; import org.wise.portal.service.run.RunService; +import org.wise.portal.service.student.StudentService; +import org.wise.portal.service.user.UserService; import org.wise.portal.service.workgroup.WorkgroupService; @ExtendWith(EasyMockExtension.class) @@ -35,32 +49,65 @@ public class SurveyAPIControllerTest { private Run run; private TestingAuthenticationToken authority; private SecurityContext securityContext; + private UserImpl studentUser = new UserImpl(); + private StudentUserDetails studentUserDetails = new StudentUserDetails(); + List workgroups; @TestSubject SurveyAPIController surveyAPIController = new SurveyAPIController(); + @Mock + AuthenticationManager authenticationManager; + @Mock HttpServletResponse httpServletResponse; @Mock HttpServletRequest httpServletRequest; + @Mock + HttpSession httpSession; + @Mock RunService runService; + @Mock + StudentService studentService; + + @Mock + UserService userService; + + @Mock + UserDetailsService userDetailsService; + @Mock WorkgroupService workgroupService; + private static final String[] periodnames = { "1", "2", "3", "6", "9", "10", "sunflower" }; + @BeforeEach public void setUp() { run = new RunImpl(); run.setId(1L); + run.setIsSurvey(true); + Set periods = new TreeSet(); + for (String periodname : periodnames) { + Group period = new PersistentGroup(); + period.setName(periodname); + if (periodname.equals("1")) { + period.addMember(studentUser); + } + periods.add(period); + } + run.setPeriods(periods); + workgroups = new ArrayList(); } - SecurityContext getSecurityContext(String role, String authorityName) { - authority = new TestingAuthenticationToken(role, + SecurityContext getSecurityContext(Object principal, String authorityName) { + authority = new TestingAuthenticationToken(principal, new GrantedAuthority[] { new SimpleGrantedAuthority(authorityName) }); authority.setAuthenticated(true); + authority.setDetails(new StudentUserDetails()); securityContext = new SecurityContextImpl(); securityContext.setAuthentication(authority); return securityContext; @@ -80,17 +127,17 @@ public void launchSurveyRun_NotASurvey_RedirectHomePage() throws Exception { } @Test - public void launchSurveyRun_AlreadySignedIn_RedirectLogOutPage() throws Exception { - httpServletResponse.sendRedirect("/survey/logout"); + public void launchSurveyRun_AlreadyAssociatedWithRun_RedirectUnit() throws Exception { + httpServletResponse.sendRedirect("/student/unit/1"); expectLastCall(); replay(httpServletResponse); - run.setIsSurvey(true); expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); replay(runService); - SecurityContextHolder.setContext(getSecurityContext("student", "ROLE_STUDENT")); + expect(userService.retrieveStudentById(null)).andReturn(studentUser); + replay(userService); + SecurityContextHolder.setContext(getSecurityContext(studentUserDetails, "ROLE_STUDENT")); surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); - verify(httpServletResponse); - verify(runService); + verify(httpServletResponse, runService, userService); } @Test @@ -98,20 +145,17 @@ public void launchSurveyRun_OverWorkgroupLimit_RedirectWorkgroupLimitPage() thro httpServletResponse.sendRedirect("/survey/workgroupLimitReached"); expectLastCall(); replay(httpServletResponse); - run.setIsSurvey(false); + expect(userService.retrieveStudentById(1L)).andReturn(new UserImpl()); expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); replay(runService); SecurityContextHolder.setContext(getSecurityContext("anonymousUser", "ROLE_ANONYMOUS")); - List workgroups = new ArrayList(); for (int i = 0; i < 1005; i++) { workgroups.add(new WorkgroupImpl()); } expect(workgroupService.getWorkgroupsForRun(run)).andReturn(workgroups); replay(workgroupService); surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); - verify(httpServletResponse); - verify(runService); - verify(workgroupService); + verify(httpServletResponse, runService, workgroupService); } @Test @@ -119,15 +163,22 @@ public void launchSurveyRun_NoIssues_RedirectUnit() throws Exception { httpServletResponse.sendRedirect("/student/unit/1"); expectLastCall(); replay(httpServletResponse); - run.setIsSurvey(false); expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); replay(runService); + studentUser.setUserDetails(studentUserDetails); + expect(userService.createUser(studentUserDetails)).andReturn(studentUser); + replay(userService); SecurityContextHolder.setContext(getSecurityContext("anonymousUser", "ROLE_ANONYMOUS")); expect(workgroupService.getWorkgroupsForRun(run)).andReturn(new ArrayList()); replay(workgroupService); + expect(userDetailsService.loadAuthorityByName("ROLE_SURVEY_STUDENT")).andReturn(null); + replay(userDetailsService); + expect(httpServletRequest.getSession(true)).andReturn(httpSession); + replay(httpServletRequest); + studentService.addStudentToRun(isA(User.class), isA(Projectcode.class)); + expectLastCall(); + replay(studentService); surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); - verify(httpServletResponse); - verify(runService); - verify(workgroupService); + verify(httpServletResponse, runService, workgroupService, studentService); } } From 50202569203bc75b6435dafb32969516e8c9e579 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Mon, 2 Jun 2025 16:21:38 -0700 Subject: [PATCH 20/22] Redirect to homepage if run is not active. --- .../survey/SurveyAPIController.java | 13 ++++++--- .../survey/SurveyAPIControllerTest.java | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 3a33e2b27..21f76edf3 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -62,16 +62,21 @@ public void launchSurveyRun(@PathVariable String code, HttpServletResponse respo HttpServletRequest request) throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, StudentUserAlreadyAssociatedWithRunException, RunHasEndedException { - Projectcode projectCode = new Projectcode(code); Run run = runService.retrieveRunByRuncode(projectCode.getRuncode()); - if (run.isSurvey()) { + if (run.isSurvey() && isActive(run)) { handleSurveyLaunched(response, request, run, projectCode); } else { sendRedirect(response, "/"); } } + private boolean isActive(Run run) { + Date now = new Date(); + Date endTime = run.getEndtime(); + return run.getStarttime().before(now) && (endTime == null || endTime.after(now)); + } + private void handleSurveyLaunched(HttpServletResponse response, HttpServletRequest request, Run run, Projectcode projectCode) throws AuthorityNotFoundException, IOException, DuplicateUsernameException, ObjectNotFoundException, PeriodNotFoundException, @@ -103,11 +108,11 @@ private Object getSecurityContextHolderPrincipal() { return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); } - private Boolean isStudentAssociatedWithRun(Run run, StudentUserDetails principal) { + private boolean isStudentAssociatedWithRun(Run run, StudentUserDetails principal) { return run.isStudentAssociatedToThisRun(userService.retrieveStudentById((principal).getId())); } - private Boolean underWorkgroupLimit(Run run) { + private boolean underWorkgroupLimit(Run run) { return workgroupService.getWorkgroupsForRun(run).size() <= 1000; } diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java index 3750b134d..f35471537 100644 --- a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java +++ b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java @@ -7,6 +7,7 @@ import static org.easymock.EasyMock.verify; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -90,6 +91,7 @@ public void setUp() { run = new RunImpl(); run.setId(1L); run.setIsSurvey(true); + run.setStarttime(new Date(System.currentTimeMillis() - 3600 * 1000)); Set periods = new TreeSet(); for (String periodname : periodnames) { Group period = new PersistentGroup(); @@ -126,6 +128,32 @@ public void launchSurveyRun_NotASurvey_RedirectHomePage() throws Exception { verify(runService); } + @Test + public void launchSurveyRun_RunInFuture_RedirectHomePage() throws Exception { + httpServletResponse.sendRedirect("/"); + expectLastCall(); + replay(httpServletResponse); + run.setStarttime(new Date(System.currentTimeMillis() + 3600 * 1000)); // Future start time + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + } + + @Test + public void launchSurveyRun_RunInPast_RedirectHomePage() throws Exception { + httpServletResponse.sendRedirect("/"); + expectLastCall(); + replay(httpServletResponse); + run.setEndtime(new Date(System.currentTimeMillis() - 3600 * 1000)); // Past end time + expect(runService.retrieveRunByRuncode("dog1234")).andReturn(run); + replay(runService); + surveyAPIController.launchSurveyRun("dog1234-1", httpServletResponse, httpServletRequest); + verify(httpServletResponse); + verify(runService); + } + @Test public void launchSurveyRun_AlreadyAssociatedWithRun_RedirectUnit() throws Exception { httpServletResponse.sendRedirect("/student/unit/1"); From fc1fe6ecbcadc2785505b37d29dc28f0cb422447 Mon Sep 17 00:00:00 2001 From: Hiroki Terashima Date: Tue, 3 Jun 2025 15:38:26 -0700 Subject: [PATCH 21/22] Change password from null to random string. Set firstname to be more random so we can generate unique usernames more often. Set locale, last login time and language. --- .../survey/SurveyAPIController.java | 23 +++++++++++-------- .../survey/SurveyAPIControllerTest.java | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java index 21f76edf3..a475e5c71 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIController.java @@ -21,11 +21,13 @@ import java.io.IOException; import java.util.Date; +import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -91,8 +93,9 @@ && isStudentAssociatedWithRun(run, (StudentUserDetails) principal)) { SecurityContextHolder.getContext().setAuthentication(null); } if (underWorkgroupLimit(run)) { - User user = this.createNewStudentAccount(); - loginStudent(request, user); + String password = RandomStringUtils.randomAlphanumeric(10); + User user = this.createNewStudentAccount(request.getLocale(), password); + loginStudent(request, user, password); studentService.addStudentToRun(user, projectCode); sendRedirect(response, "/student/unit/" + run.getId()); } else { @@ -116,9 +119,9 @@ private boolean underWorkgroupLimit(Run run) { return workgroupService.getWorkgroupsForRun(run).size() <= 1000; } - private void loginStudent(HttpServletRequest request, User user) { + private void loginStudent(HttpServletRequest request, User user, String password) { UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken( - user.getUserDetails().getUsername(), "null"); + user.getUserDetails().getUsername(), password); Authentication auth = authenticationManager.authenticate(authReq); SecurityContext sc = SecurityContextHolder.getContext(); sc.setAuthentication(auth); @@ -126,16 +129,18 @@ private void loginStudent(HttpServletRequest request, User user) { session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc); } - private User createNewStudentAccount() + private User createNewStudentAccount(Locale locale, String password) throws AuthorityNotFoundException, DuplicateUsernameException { StudentUserDetails sud = new StudentUserDetails(); - sud.setFirstname("survey_student"); - sud.setLastname(Integer.toString((int) Math.ceil(Math.random() * 10000))); + sud.setFirstname("survey_student_" + RandomStringUtils.randomAlphanumeric(10)); + sud.setLastname(RandomStringUtils.randomAlphanumeric(10)); sud.setBirthday(new Date()); - sud.setPassword("null"); + sud.setPassword(password); sud.setGender(Gender.UNSPECIFIED); sud.setEmailAddress("null@null.com"); - sud.setLanguage("null"); + sud.setLanguage(locale.getLanguage()); + sud.setNumberOfLogins(1); + sud.setLastLoginTime(new Date()); User user = userService.createUser(sud); user.getUserDetails().addAuthority( diff --git a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java index f35471537..511c3d5de 100644 --- a/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java +++ b/src/test/java/org/wise/portal/presentation/web/controllers/survey/SurveyAPIControllerTest.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.TreeSet; @@ -201,6 +202,7 @@ public void launchSurveyRun_NoIssues_RedirectUnit() throws Exception { replay(workgroupService); expect(userDetailsService.loadAuthorityByName("ROLE_SURVEY_STUDENT")).andReturn(null); replay(userDetailsService); + expect(httpServletRequest.getLocale()).andReturn(new Locale("en")); expect(httpServletRequest.getSession(true)).andReturn(httpSession); replay(httpServletRequest); studentService.addStudentToRun(isA(User.class), isA(Projectcode.class)); From 481e64b020759dd89ff6d5ebeb93633b2f7df58a Mon Sep 17 00:00:00 2001 From: Jonathan Lim-Breitbart Date: Wed, 4 Jun 2025 14:55:46 -0700 Subject: [PATCH 22/22] Add isSurvey to run config --- .../presentation/web/controllers/InformationController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/InformationController.java b/src/main/java/org/wise/portal/presentation/web/controllers/InformationController.java index f7e272ee1..b0fb2d753 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/InformationController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/InformationController.java @@ -679,6 +679,7 @@ private void getRunConfigParameters(HttpServletRequest request, JSONObject confi config.put("startTime", run.getStartTimeMilliseconds()); config.put("endTime", run.getEndTimeMilliseconds()); config.put("isLockedAfterEndDate", run.isLockedAfterEndDate()); + config.put("isSurvey", run.isSurvey()); } private void printConfigToResponse(HttpServletResponse response, JSONObject config) @@ -785,6 +786,7 @@ private void addDummyUserInfoToConfig(JSONObject config) { /** * Gets the workgroup for the logged in user + * * @param run * @return Workgroup for the logged in user */