Skip to content

Commit 9b22a0c

Browse files
plukasewottenhoff
authored andcommitted
SAK-32608: Extend CandidateDetailProvider to provide institutional numeric ids (student numbers) for use in Gradebook (sakaiproject#4496)
* SAK-32608: Extend CandidateDetailProvider to provide institutional numeric ids (student numbers) for use in Gradebook * SAK-32608: fixed issue with category column positioning when student number column is visible * SAK-32608: added api method to bypass candidate student number visibility permission to facilitate business cases that require the number
1 parent 6220894 commit 9b22a0c

File tree

31 files changed

+659
-29
lines changed

31 files changed

+659
-29
lines changed

edu-services/gradebook-service/api/src/java/org/sakaiproject/service/gradebook/shared/GradebookService.java

+6
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,12 @@ public boolean isAssignmentDefined(String gradebookUid, String assignmentTitle)
583583
*/
584584
public boolean currentUserHasViewOwnGradesPerm(String gradebookUid);
585585

586+
/**
587+
* @param gradebookUid
588+
* @return true if the current user has the gradebook.viewStudentNumbers permission
589+
*/
590+
public boolean currentUserHasViewStudentNumbersPerm(String gradebookUid);
591+
586592
/**
587593
* Get the grade records for the given list of students and the given assignment.
588594
* This can only be called by an instructor or TA that has access, not student.

edu-services/gradebook-service/api/src/java/org/sakaiproject/tool/gradebook/facades/Authz.java

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public interface Authz {
3535
public boolean isUserAbleToGradeAll(String gradebookUid, String userUid);
3636
public boolean isUserAbleToEditAssessments(String gradebookUid);
3737
public boolean isUserAbleToViewOwnGrades(String gradebookUid);
38+
public boolean isUserAbleToViewStudentNumbers(String gradebookUid);
3839
public boolean isUserHasGraderPermissions(String gradebookUid);
3940
public boolean isUserHasGraderPermissions(Long gradebookId);
4041
public boolean isUserHasGraderPermissions(Long gradebookId, String userUid);

edu-services/gradebook-service/impl/src/java/org/sakaiproject/component/gradebook/GradebookServiceHibernateImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,12 @@ public boolean currentUserHasViewOwnGradesPerm(String gradebookUid) {
17421742
return authz.isUserAbleToViewOwnGrades(gradebookUid);
17431743
}
17441744

1745+
@Override
1746+
public boolean currentUserHasViewStudentNumbersPerm(String gradebookUid)
1747+
{
1748+
return authz.isUserAbleToViewStudentNumbers(gradebookUid);
1749+
}
1750+
17451751
@Override
17461752
public List<GradeDefinition> getGradesForStudentsForItem(final String gradebookUid, final Long gradableObjectId, List<String> studentIds) {
17471753
if (gradableObjectId == null) {

edu-services/gradebook-service/impl/src/java/org/sakaiproject/tool/gradebook/facades/sakai2impl/AuthzSakai2Impl.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ public class AuthzSakai2Impl extends AuthzSectionsImpl implements Authz {
5353
PERMISSION_GRADE_ALL = "gradebook.gradeAll",
5454
PERMISSION_GRADE_SECTION = "gradebook.gradeSection",
5555
PERMISSION_EDIT_ASSIGNMENTS = "gradebook.editAssignments",
56-
PERMISSION_VIEW_OWN_GRADES = "gradebook.viewOwnGrades";
56+
PERMISSION_VIEW_OWN_GRADES = "gradebook.viewOwnGrades",
57+
PERMISSION_VIEW_STUDENT_NUMBERS = "gradebook.viewStudentNumbers";
5758

5859
/**
5960
* Perform authorization-specific framework initializations for the Gradebook.
@@ -75,6 +76,10 @@ public void init() {
7576
if(!registered.contains(PERMISSION_VIEW_OWN_GRADES)) {
7677
FunctionManager.registerFunction(PERMISSION_VIEW_OWN_GRADES);
7778
}
79+
80+
if(!registered.contains(PERMISSION_VIEW_STUDENT_NUMBERS)) {
81+
FunctionManager.registerFunction(PERMISSION_VIEW_STUDENT_NUMBERS);
82+
}
7883
}
7984

8085
public boolean isUserAbleToGrade(String gradebookUid) {
@@ -123,6 +128,11 @@ public boolean isUserAbleToEditAssessments(String gradebookUid) {
123128
public boolean isUserAbleToViewOwnGrades(String gradebookUid) {
124129
return hasPermission(gradebookUid, PERMISSION_VIEW_OWN_GRADES);
125130
}
131+
132+
public boolean isUserAbleToViewStudentNumbers(String gradebookUid)
133+
{
134+
return hasPermission(gradebookUid, PERMISSION_VIEW_STUDENT_NUMBERS);
135+
}
126136

127137
private boolean hasPermission(String gradebookUid, String permission) {
128138
return SecurityService.unlock(permission, SiteService.siteReference(gradebookUid));

edu-services/gradebook-service/impl/src/java/org/sakaiproject/tool/gradebook/facades/sections/AuthzSectionsImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ public boolean isUserAbleToViewOwnGrades(String gradebookUid) {
116116
return getSectionAwareness().isSiteMemberInRole(gradebookUid, userUid, Role.STUDENT);
117117
}
118118

119+
public boolean isUserAbleToViewStudentNumbers(String gradebookUid)
120+
{
121+
String userUid = authn.getUserUid();
122+
return getSectionAwareness().isSiteMemberInRole(gradebookUid, userUid, Role.INSTRUCTOR);
123+
}
124+
119125
public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long itemId, String studentUid) {
120126
if (itemId == null || studentUid == null || gradebookUid == null) {
121127
throw new IllegalArgumentException("Null parameter(s) in AuthzSectionsServiceImpl.isUserAbleToGradeItemForStudent");

gradebookng/tool/src/java/org/sakaiproject/gradebookng/GradebookNgApplication.properties

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ error.concurrentedit=Concurrent edits have been detected. Refresh the tool to se
7070

7171
column.header.section = Section
7272
column.header.students = Students
73+
column.header.studentNumber = Student Number
7374
column.header.coursegrade = Course Grade
7475

7576
filter.students = Filter students
@@ -246,6 +247,7 @@ importExport.export.advancedOption.description = Select from the options below t
246247
importExport.export.advancedOption.warning = Customized exports can only be imported back into the system if Student ID and Student Name are retained in the first and second columns and all other formatting conventions are followed.
247248
importExport.export.advancedOption.exportFormat = Export File Format
248249
importExport.export.advancedOption.includeStudentName = Student Name
250+
importExport.export.advancedOption.includeStudentNumber = Student Number
249251
importExport.export.advancedOption.includePoints = Total Points
250252
importExport.export.advancedOption.includeLastLogDate = Last Log Date
251253
importExport.export.advancedOption.includeCourseGrade = Course Grade
@@ -256,6 +258,7 @@ importExport.export.advancedOption.includeGradeItemScores = Gradebook Item Score
256258
importExport.export.advancedOption.includeGradeItemComments = Gradebook Item Comments
257259
importExport.export.csv.headers.studentId = Student ID
258260
importExport.export.csv.headers.studentName = Student Name
261+
importExport.export.csv.headers.studentNumber = Student Number
259262
importExport.export.csv.headers.points = Total Points
260263
importExport.export.csv.headers.courseGrade = Course Grade
261264
importExport.export.csv.headers.calculatedGrade = Calculated Grade

gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/GradebookNgBusinessService.java

+66-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.List;
1313
import java.util.Locale;
1414
import java.util.Map;
15+
import java.util.Optional;
1516
import java.util.Set;
1617
import java.util.TreeMap;
1718
import java.util.stream.Collectors;
@@ -70,6 +71,7 @@
7071

7172
import lombok.Setter;
7273
import lombok.extern.slf4j.Slf4j;
74+
import org.sakaiproject.user.api.CandidateDetailProvider;
7375

7476
/**
7577
* Business service for GradebookNG
@@ -114,6 +116,9 @@ public class GradebookNgBusinessService {
114116

115117
@Setter
116118
private SecurityService securityService;
119+
120+
@Setter
121+
private CandidateDetailProvider candidateDetailProvider;
117122

118123
@Setter
119124
private ServerConfigurationService serverConfigurationService;
@@ -684,6 +689,8 @@ public List<GbStudentGradeInfo> buildGradeMatrix(final List<Assignment> assignme
684689
} catch (final GbAccessDeniedException e) {
685690
throw new GbException("Error getting role for current user", e);
686691
}
692+
693+
Optional<Site> site = getCurrentSite();
687694

688695
// get uuids as list of Users.
689696
// this gives us our base list and will be sorted as per our desired
@@ -701,6 +708,18 @@ public List<GbStudentGradeInfo> buildGradeMatrix(final List<Assignment> assignme
701708
}
702709
Collections.sort(students, comp);
703710
}
711+
else if (settings.getStudentNumberSortOrder() != null)
712+
{
713+
if (site.isPresent())
714+
{
715+
Comparator<User> comp = new StudentNumberComparator(candidateDetailProvider, site.get());
716+
if (SortDirection.DESCENDING.equals(settings.getStudentNumberSortOrder()))
717+
{
718+
comp = Collections.reverseOrder(comp);
719+
}
720+
Collections.sort(students, comp);
721+
}
722+
}
704723
stopwatch.timeWithContext("buildGradeMatrix", "sortUsers", stopwatch.getTime());
705724

706725
// get course grades
@@ -727,7 +746,7 @@ public List<GbStudentGradeInfo> buildGradeMatrix(final List<Assignment> assignme
727746
for (final User student : students) {
728747

729748
// create and add the user info
730-
final GbStudentGradeInfo sg = new GbStudentGradeInfo(student);
749+
final GbStudentGradeInfo sg = new GbStudentGradeInfo(student, getStudentNumber(student, site.orElse(null)));
731750

732751
// add the course grade, including the display
733752
final CourseGrade courseGrade = courseGrades.get(student.getId());
@@ -1112,6 +1131,29 @@ public String getCurrentSiteId() {
11121131
return null;
11131132
}
11141133
}
1134+
1135+
/**
1136+
* Helper to get site. This will ONLY work in a portal site context, it will return empty otherwise (ie via an entityprovider).
1137+
*
1138+
* @return
1139+
*/
1140+
public Optional<Site> getCurrentSite()
1141+
{
1142+
String siteId = getCurrentSiteId();
1143+
if (siteId != null)
1144+
{
1145+
try
1146+
{
1147+
return Optional.of(siteService.getSite(siteId));
1148+
}
1149+
catch (IdUnusedException e)
1150+
{
1151+
// do nothing
1152+
}
1153+
}
1154+
1155+
return Optional.empty();
1156+
}
11151157

11161158
/**
11171159
* Helper to get user
@@ -1821,6 +1863,29 @@ public boolean isCourseGradeVisible(final String userUuid) {
18211863
log.warn("User: " + userUuid + " does not have a valid Gradebook related role in site: " + siteId);
18221864
return false;
18231865
}
1866+
1867+
/**
1868+
* Are student numbers visible to the current user in the current site?
1869+
*
1870+
* @return true if student numbers are visible
1871+
*/
1872+
public boolean isStudentNumberVisible()
1873+
{
1874+
User user = getCurrentUser();
1875+
Optional<Site> site = getCurrentSite();
1876+
return user != null && site.isPresent() && candidateDetailProvider.isInstitutionalNumericIdEnabled(site.get())
1877+
&& gradebookService.currentUserHasViewStudentNumbersPerm(getGradebook().getUid());
1878+
}
1879+
1880+
public String getStudentNumber(User u, Site site)
1881+
{
1882+
if (site == null)
1883+
{
1884+
return "";
1885+
}
1886+
1887+
return candidateDetailProvider.getInstitutionalNumericId(u, site).orElse("");
1888+
}
18241889

18251890
/**
18261891
* Build a list of group references to site membership (as uuids) for the groups that are viewable for the current user.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.sakaiproject.gradebookng.business;
2+
3+
import java.util.Comparator;
4+
import lombok.RequiredArgsConstructor;
5+
import org.sakaiproject.site.api.Site;
6+
import org.sakaiproject.user.api.CandidateDetailProvider;
7+
import org.sakaiproject.user.api.User;
8+
9+
/**
10+
* Comparator class for sorting a list of users by student number
11+
* @author plukasew
12+
*/
13+
@RequiredArgsConstructor
14+
public class StudentNumberComparator implements Comparator<User>
15+
{
16+
private final CandidateDetailProvider provider;
17+
private final Site site;
18+
19+
@Override
20+
public int compare(final User u1, final User u2)
21+
{
22+
String stunum1 = provider.getInstitutionalNumericId(u1, site).orElse("");
23+
String stunum2 = provider.getInstitutionalNumericId(u2, site).orElse("");
24+
return stunum1.compareTo(stunum2);
25+
}
26+
}

gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/model/GbStudentGradeInfo.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public class GbStudentGradeInfo implements Serializable {
3232

3333
@Getter
3434
private String studentEid;
35+
36+
@Getter
37+
private String studentNumber;
3538

3639
@Getter
3740
@Setter
@@ -46,12 +49,17 @@ public class GbStudentGradeInfo implements Serializable {
4649
public GbStudentGradeInfo() {
4750
}
4851

49-
public GbStudentGradeInfo(final User u) {
52+
public GbStudentGradeInfo(final User u)
53+
{
54+
this(u, "");
55+
}
56+
public GbStudentGradeInfo(final User u, final String studentNumber) {
5057
this.studentUuid = u.getId();
5158
this.studentEid = u.getEid();
5259
this.studentFirstName = u.getFirstName();
5360
this.studentLastName = u.getLastName();
5461
this.studentDisplayName = u.getDisplayName();
62+
this.studentNumber = studentNumber;
5563
this.grades = new HashMap<Long, GbGradeInfo>();
5664
this.categoryAverages = new HashMap<Long, Double>();
5765
}

gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbHeadersToolbar.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<wicket:panel xmlns:wicket="http://wicket.apache.org">
22
<tr wicket:id="categoriesRow" class="gb-categories-row" role="row">
3-
<th colspan="3"><!-- empty --></th>
3+
<th wicket:id="empty"><!-- empty --></th>
44
<th wicket:id="categories" scope="col" role="columnheader">
55
<span class="gb-category-label">
66
<span wicket:id="extraCreditCategoryFlag" class="gb-category-extra-credit"></span>

gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbHeadersToolbar.java

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.apache.wicket.markup.html.list.ListItem;
1616
import org.apache.wicket.markup.html.list.ListView;
1717
import org.apache.wicket.model.IModel;
18+
import org.apache.wicket.model.Model;
1819
import org.apache.wicket.model.StringResourceModel;
1920
import org.sakaiproject.gradebookng.business.GbCategoryType;
2021
import org.sakaiproject.gradebookng.business.util.FormatHelper;
@@ -44,6 +45,10 @@ public void onInitialize() {
4445

4546
if (categoriesEnabled && settings.isCategoriesEnabled()) {
4647
final WebMarkupContainer categoriesRow = new WebMarkupContainer("categoriesRow");
48+
49+
final Label emptyCat = new Label("empty", Model.of(""));
50+
emptyCat.add(new AttributeModifier("colspan", (Integer) modelData.get("fixedColCount")));
51+
categoriesRow.add(emptyCat);
4752

4853
final List<Assignment> assignments = (List<Assignment>) modelData.get("assignments");
4954
List<CategoryDefinition> categories = (List<CategoryDefinition>) modelData.get("categories");

gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GradebookUiSettings.java

+13
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public class GradebookUiSettings implements Serializable {
6868
*/
6969
@Getter
7070
private SortDirection studentSortOrder;
71+
72+
/**
73+
* The direction to sort the student number column
74+
*/
75+
@Getter
76+
private SortDirection studentNumberSortOrder;
7177

7278
/**
7379
* For sorting based on coursegrade
@@ -187,12 +193,19 @@ public void setStudentSortOrder(SortDirection sortOrder) {
187193
resetSortOrder();
188194
this.studentSortOrder = sortOrder;
189195
}
196+
197+
public void setStudentNumberSortOrder(SortDirection sortOrder)
198+
{
199+
resetSortOrder();
200+
studentNumberSortOrder = sortOrder;
201+
}
190202

191203
private void resetSortOrder() {
192204
this.courseGradeSortOrder = null;
193205
this.categorySortOrder = null;
194206
this.assignmentSortOrder = null;
195207
this.studentSortOrder = null;
208+
studentNumberSortOrder = null;
196209
}
197210

198211
@Override

0 commit comments

Comments
 (0)