Skip to content

Commit

Permalink
More work on processing uploading grades.
Browse files Browse the repository at this point in the history
Added some unit tests.
  • Loading branch information
maurercw committed Jan 31, 2015
1 parent fead5f5 commit 1af8fd1
Show file tree
Hide file tree
Showing 14 changed files with 501 additions and 75 deletions.
6 changes: 6 additions & 0 deletions tool/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@
<artifactId>poi-ooxml</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.sakaiproject.gradebookng.business.model.ImportColumn;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.LinkedHashMap;
import java.util.Map;

Expand All @@ -22,15 +25,45 @@ public class BaseImportHelper {
* @param line the already split line
* @return
*/
protected static Map<Integer,String> mapHeaderRow(String[] line) {
Map<Integer,String> mapping = new LinkedHashMap<Integer,String>();
protected static Map<Integer,ImportColumn> mapHeaderRow(String[] line) {
Map<Integer,ImportColumn> mapping = new LinkedHashMap<Integer,ImportColumn>();
for(int i=0;i<line.length;i++){
mapping.put(i, trim(line[i]));
mapping.put(i, parseHeaderForImportColumn(trim(line[i])));
}

return mapping;
}

private static ImportColumn parseHeaderForImportColumn(String headerValue) {
ImportColumn importColumn = new ImportColumn();
MessageFormat mf = new MessageFormat(ImportGradesHelper.ASSIGNMENT_HEADER_PATTERN);
Object[] parsedObject;
try {
parsedObject = mf.parse(headerValue);
importColumn.setColumnTitle((String)parsedObject[0]);
importColumn.setType(ImportColumn.TYPE_ITEM_WITH_POINTS);
importColumn.setPoints((String)parsedObject[1]);
} catch (ParseException e) {
mf = new MessageFormat(ImportGradesHelper.ASSIGNMENT_HEADER_COMMENT_PATTERN);
try {
parsedObject = mf.parse(headerValue);
importColumn.setColumnTitle((String)parsedObject[0]);
importColumn.setType(ImportColumn.TYPE_ITEM_WITH_COMMENTS);
} catch (ParseException e1) {
mf = new MessageFormat(ImportGradesHelper.HEADER_STANDARD_PATTERN);
try {
parsedObject = mf.parse(headerValue);
importColumn.setColumnTitle((String)parsedObject[0]);
importColumn.setType(ImportColumn.TYPE_REGULAR);
} catch (ParseException e2) {
throw new RuntimeException("Error parsing grade import", e2);
}
}
}

return importColumn;
}

/**
* Takes a header Row from an Excel file and maps it the same as the CSV mapper does.
* Only handles string typed cells.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.gradebookng.business.model.ImportedGrade;
import org.sakaiproject.gradebookng.business.model.ImportedGradeItem;
import org.sakaiproject.gradebookng.business.model.ImportedGradeWrapper;
import org.sakaiproject.gradebookng.business.model.*;
import org.sakaiproject.gradebookng.tool.model.AssignmentStudentGradeInfo;
import org.sakaiproject.gradebookng.tool.model.GradeInfo;
import org.sakaiproject.gradebookng.tool.model.StudentGradeInfo;
import org.sakaiproject.service.gradebook.shared.Assignment;
import org.sakaiproject.util.BaseResourcePropertiesEdit;

import java.io.IOException;
Expand All @@ -20,6 +22,7 @@
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -33,22 +36,23 @@ public class ImportGradesHelper extends BaseImportHelper {
private static final String IMPORT_USER_NAME="Student Name";

protected static final String ASSIGNMENT_HEADER_PATTERN = "{0} [{1}]";
protected static final String ASSIGNMENT_HEADER_COMMENT_PATTERN = "*/ {0} Comments */";;
protected static final String ASSIGNMENT_HEADER_COMMENT_PATTERN = "*/ {0} Comments */";
protected static final String HEADER_STANDARD_PATTERN = "{0}";


/**
* Parse a CSV into a list of ImportedGrade objects. Returns list if ok, or null if error
* @param is InputStream of the data to parse
* @return
*/
public static List<ImportedGrade> parseCsv(InputStream is) {
public static ImportedGradeWrapper parseCsv(InputStream is) {

//manually parse method so we can support arbitrary columns
CSVReader reader = new CSVReader(new InputStreamReader(is));
String [] nextLine;
int lineCount = 0;
List<ImportedGrade> list = new ArrayList<ImportedGrade>();
Map<Integer,String> mapping = null;
Map<Integer,ImportColumn> mapping = null;

try {
while ((nextLine = reader.readNext()) != null) {
Expand All @@ -74,10 +78,10 @@ public static List<ImportedGrade> parseCsv(InputStream is) {
}

ImportedGradeWrapper importedGradeWrapper = new ImportedGradeWrapper();
// importedGradeWrapper.setAssignmentNames();
importedGradeWrapper.setColumns(mapping.values());
importedGradeWrapper.setImportedGrades(list);

return list;
return importedGradeWrapper;
}

/**
Expand All @@ -87,11 +91,11 @@ public static List<ImportedGrade> parseCsv(InputStream is) {
* @param is InputStream of the data to parse
* @return
*/
public static List<ImportedGrade> parseXls(InputStream is) {
public static ImportedGradeWrapper parseXls(InputStream is) {

int lineCount = 0;
List<ImportedGrade> list = new ArrayList<ImportedGrade>();
Map<Integer,String> mapping = null;
Map<Integer,ImportColumn> mapping = null;

try {
Workbook wb = WorkbookFactory.create(is);
Expand All @@ -115,28 +119,31 @@ public static List<ImportedGrade> parseXls(InputStream is) {
return null;
}

return list;
}

private static List<String> processAssignmentNames(Map<Integer,String> mapping) {
List<String> assignmentNames = new ArrayList<String>();
for(Map.Entry<Integer,String> entry: mapping.entrySet()) {
int i = entry.getKey();
//trim in case some whitespace crept in
String col = trim(entry.getValue());

//Find all columns that are not well known
if(!StringUtils.equals(col, IMPORT_USER_ID) && !StringUtils.equals(col, IMPORT_USER_NAME)) {

String assignmentName = parseHeaderForAssignmentName(col);
if (!assignmentNames.contains(assignmentName))
assignmentNames.add(assignmentName);
}
}
return assignmentNames;
ImportedGradeWrapper importedGradeWrapper = new ImportedGradeWrapper();
importedGradeWrapper.setColumns(mapping.values());
importedGradeWrapper.setImportedGrades(list);
return importedGradeWrapper;
}

private static String parseHeaderForAssignmentName(String headerValue) {
// private static List<ProcessedGradeItem> processAssignmentNames(Map<Integer,String> mapping) {
// List<String> assignmentNames = new ArrayList<String>();
// for(Map.Entry<Integer,String> entry: mapping.entrySet()) {
// int i = entry.getKey();
// //trim in case some whitespace crept in
// String col = trim(entry.getValue());
//
// //Find all columns that are not well known
// if(!StringUtils.equals(col, IMPORT_USER_ID) && !StringUtils.equals(col, IMPORT_USER_NAME)) {
//
// String assignmentName = parseHeaderForAssignmentName(col);
// if (!assignmentNames.contains(assignmentName))
// assignmentNames.add(assignmentName);
// }
// }
// return assignmentNames;
// }

private static Object[] parseHeaderForAssignmentName(String headerValue) {
MessageFormat mf = new MessageFormat(ImportGradesHelper.ASSIGNMENT_HEADER_PATTERN);
Object[] parsedObject;
try {
Expand All @@ -150,7 +157,7 @@ private static String parseHeaderForAssignmentName(String headerValue) {
}
}

return (String)parsedObject[0];
return parsedObject;
}

private static boolean isCommentsColumn(String headerValue) {
Expand Down Expand Up @@ -180,44 +187,47 @@ private static boolean isGradeColumn(String headerValue) {
* @param mapping
* @return
*/
private static ImportedGrade mapLine(String[] line, Map<Integer,String> mapping){
private static ImportedGrade mapLine(String[] line, Map<Integer,ImportColumn> mapping){

ImportedGrade grade = new ImportedGrade();
ResourceProperties p = new BaseResourcePropertiesEdit();

for(Map.Entry<Integer,String> entry: mapping.entrySet()) {
for(Map.Entry<Integer,ImportColumn> entry: mapping.entrySet()) {
int i = entry.getKey();
//trim in case some whitespace crept in
String col = trim(entry.getValue());
ImportColumn importColumn = entry.getValue();
// String col = trim(entry.getValue());



//now check each of the main properties in turn to determine which one to set, otherwise set into props
if(StringUtils.equals(col, IMPORT_USER_ID)) {
if(StringUtils.equals(importColumn.getColumnTitle(), IMPORT_USER_ID)) {
grade.setStudentId(trim(line[i]));
} else if(StringUtils.equals(col, IMPORT_USER_NAME)) {
} else if(StringUtils.equals(importColumn.getColumnTitle(), IMPORT_USER_NAME)) {
grade.setStudentName(trim(line[i]));
} else if(isGradeColumn(col)) {
String assignmentName = parseHeaderForAssignmentName(col);
} else if(ImportColumn.TYPE_ITEM_WITH_POINTS==importColumn.getType()) {
String assignmentName = importColumn.getColumnTitle();
ImportedGradeItem importedGradeItem = grade.getGradeItemMap().get(assignmentName);
if (importedGradeItem == null) {
importedGradeItem = new ImportedGradeItem();
grade.getGradeItemMap().put(assignmentName, importedGradeItem);
importedGradeItem.setGradeItemName(assignmentName);
}
importedGradeItem.setGradeItemScore(trim(line[i]));
} else if(isCommentsColumn(col)) {
String assignmentName = parseHeaderForAssignmentName(col);
} else if(ImportColumn.TYPE_ITEM_WITH_COMMENTS==importColumn.getType()) {
String assignmentName = importColumn.getColumnTitle();
ImportedGradeItem importedGradeItem = grade.getGradeItemMap().get(assignmentName);
if (importedGradeItem == null) {
importedGradeItem = new ImportedGradeItem();
grade.getGradeItemMap().put(assignmentName, importedGradeItem);
importedGradeItem.setGradeItemName(assignmentName);
}
importedGradeItem.setGradeItemComment(trim(line[i]));
} else {

//only add if not blank
if(StringUtils.isNotBlank(trim(line[i]))) {
p.addProperty(col, trim(line[i]));
p.addProperty(importColumn.getColumnTitle(), trim(line[i]));
}
}
}
Expand All @@ -227,7 +237,110 @@ private static ImportedGrade mapLine(String[] line, Map<Integer,String> mapping)
}


public static void processImportedGrades(List<ImportedGrade> importedGrades) {
public static List<ProcessedGradeItem> processImportedGrades(ImportedGradeWrapper importedGradeWrapper,
List<Assignment> assignments, List<StudentGradeInfo> currentGrades) {
List<ProcessedGradeItem> processedGradeItems = new ArrayList<ProcessedGradeItem>();
Map<String, Long> assignmentNameMap = new HashMap<String, Long>();

Map<Long, AssignmentStudentGradeInfo> transformedGradeMap = transformCurrentGrades(currentGrades);

//Map the assignment name back to the Id
for (Assignment assignment : assignments) {
assignmentNameMap.put(assignment.getName(), assignment.getId());
}


for (ImportColumn column : importedGradeWrapper.getColumns()) {
ProcessedGradeItem processedGradeItem = new ProcessedGradeItem();

if (column.getType() == ImportColumn.TYPE_ITEM_WITH_POINTS) {
processedGradeItem.setItemTitle(column.getColumnTitle());
processedGradeItem.setItemPointValue(column.getPoints());

Long assignmentId = assignmentNameMap.get(column.getColumnTitle());

int status = determineStatus(column, assignmentId, importedGradeWrapper, transformedGradeMap);

processedGradeItem.setItemId(assignmentId);
processedGradeItem.setStatus(status);
processedGradeItems.add(processedGradeItem);

} else if (column.getType() == ImportColumn.TYPE_ITEM_WITH_COMMENTS) {
processedGradeItem.setItemTitle(" " + column.getColumnTitle() + " Comments");
processedGradeItem.setItemPointValue("N/A");

Long assignmentId = assignmentNameMap.get(column.getColumnTitle());

int status = determineStatus(column, assignmentId, importedGradeWrapper, transformedGradeMap);

processedGradeItem.setItemId(assignmentId);
processedGradeItem.setStatus(status);

processedGradeItems.add(processedGradeItem);
}
}

return processedGradeItems;

}

private static int determineStatus(ImportColumn column, Long assignmentId, ImportedGradeWrapper importedGradeWrapper,
Map<Long, AssignmentStudentGradeInfo> transformedGradeMap) {
int status = ProcessedGradeItem.STATUS_UNKNOWN;
if (assignmentId == null) {
status = ProcessedGradeItem.STATUS_NEW;
} else {
for (ImportedGrade importedGrade : importedGradeWrapper.getImportedGrades()) {
AssignmentStudentGradeInfo assignmentStudentGradeInfo = transformedGradeMap.get(assignmentId);
ImportedGradeItem importedGradeItem = importedGrade.getGradeItemMap().get(column.getColumnTitle());
GradeInfo actualGradeInfo = assignmentStudentGradeInfo.getStudentGrades().get(importedGrade.getStudentId());
if (actualGradeInfo == null) {
// status = ProcessedGradeItem.STATUS_UPDATE;
break;
}
String importedScore = importedGradeItem.getGradeItemScore();
String actualScore = actualGradeInfo.getGrade();
String importedComment = importedGradeItem.getGradeItemComment();
String actualComment = actualGradeInfo.getGradeComment();

if (column.getType() == ImportColumn.TYPE_ITEM_WITH_POINTS) {
if (!importedScore.equals(actualScore)) {
status = ProcessedGradeItem.STATUS_UPDATE;
break;
}
} else if (column.getType() == ImportColumn.TYPE_ITEM_WITH_COMMENTS) {
if (!importedComment.equals(actualComment)) {
status = ProcessedGradeItem.STATUS_UPDATE;
break;
}
}
}
// If we get here, must not have been any changes
if (status == ProcessedGradeItem.STATUS_UNKNOWN)
status = ProcessedGradeItem.STATUS_NA;
}
return status;
}

private static Map<Long, AssignmentStudentGradeInfo> transformCurrentGrades(List<StudentGradeInfo> currentGrades) {
Map<Long, AssignmentStudentGradeInfo> assignmentMap = new HashMap<Long, AssignmentStudentGradeInfo>();

for (StudentGradeInfo studentGradeInfo : currentGrades) {
for (Map.Entry<Long, GradeInfo> entry : studentGradeInfo.getGrades().entrySet()) {
Long assignmentId = entry.getKey();
AssignmentStudentGradeInfo assignmentStudentGradeInfo = assignmentMap.get(assignmentId);
if (assignmentStudentGradeInfo == null) {
assignmentStudentGradeInfo = new AssignmentStudentGradeInfo();
assignmentStudentGradeInfo.setAssignmemtId(assignmentId);
assignmentMap.put(assignmentId, assignmentStudentGradeInfo);
}
assignmentStudentGradeInfo.addGrade(studentGradeInfo.getStudentUuid(), entry.getValue());
// assignmentStudentGradeInfo.setGradeInfo(entry.getValue());
// assignmentStudentGradeInfo.setStudentId(studentGradeInfo.getStudentUuid());
}

}

return assignmentMap;
}
}
Loading

0 comments on commit 1af8fd1

Please sign in to comment.