package fi.otavanopisto.muikku.plugins.schooldatapyramus;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.inject.Inject;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import fi.otavanopisto.muikku.plugins.schooldatapyramus.entities.PyramusSchoolDataEntityFactory;
import fi.otavanopisto.muikku.plugins.schooldatapyramus.rest.PyramusClient;
import fi.otavanopisto.muikku.schooldata.SchoolDataIdentifier;
import fi.otavanopisto.muikku.schooldata.SchoolDataBridgeInternalException;
import fi.otavanopisto.muikku.schooldata.WorkspaceSchoolDataBridge;
import fi.otavanopisto.muikku.schooldata.entity.User;
import fi.otavanopisto.muikku.schooldata.entity.Workspace;
import fi.otavanopisto.muikku.schooldata.entity.WorkspaceType;
import fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser;
import fi.otavanopisto.pyramus.rest.model.Course;
import fi.otavanopisto.pyramus.rest.model.CourseDescription;
import fi.otavanopisto.pyramus.rest.model.CourseEducationSubtype;
import fi.otavanopisto.pyramus.rest.model.CourseEducationType;
import fi.otavanopisto.pyramus.rest.model.CourseOptionality;
import fi.otavanopisto.pyramus.rest.model.CourseParticipationType;
import fi.otavanopisto.pyramus.rest.model.CourseStaffMember;
import fi.otavanopisto.pyramus.rest.model.CourseStudent;
import fi.otavanopisto.pyramus.rest.model.EducationSubtype;
import fi.otavanopisto.pyramus.rest.model.EducationType;
import fi.otavanopisto.pyramus.rest.model.Subject;
public class PyramusWorkspaceSchoolDataBridge implements WorkspaceSchoolDataBridge {
@Inject
private Logger logger;
@Inject
private PyramusClient pyramusClient;
@Inject
private PyramusIdentifierMapper identifierMapper;
@Inject
private PyramusSchoolDataEntityFactory entityFactory;
@Inject
private PyramusStudentActivityMapper pyramusStudentActivityMapper;
@Inject
private WorkspaceDiscoveryWaiter workspaceDiscoveryWaiter;
@Override
public String getSchoolDataSource() {
return SchoolDataPyramusPluginDescriptor.SCHOOL_DATA_SOURCE;
}
@Override
public Workspace createWorkspace(String name, String description, WorkspaceType type, String courseIdentifierIdentifier) {
if (StringUtils.isBlank(name)) {
throw new SchoolDataBridgeInternalException("Name is required");
}
if (name.length() > 255) {
throw new SchoolDataBridgeInternalException("Name maximum length is 255 characters");
}
throw new SchoolDataBridgeInternalException("Not implemented");
}
@Override
public Workspace copyWorkspace(SchoolDataIdentifier identifier, String name, String nameExtension, String description) {
if (!getSchoolDataSource().equals(identifier.getDataSource())) {
logger.severe(String.format("Invalid workspace identfier for Pyramus bridge", identifier));
return null;
}
Long pyramusCourseId = identifierMapper.getPyramusCourseId(identifier.getIdentifier());
if (pyramusCourseId == null) {
logger.severe(String.format("Workspace identifier %s is not valid", identifier));
return null;
}
Course course = pyramusClient.get(String.format("/courses/courses/%d", pyramusCourseId), Course.class);
if (course == null) {
logger.severe(String.format("Could not find Pyramus course by id %d", pyramusCourseId));
return null;
}
List<String> copiedTags = null;
if (course.getTags() != null) {
copiedTags = new ArrayList<String>();
for (String tag : course.getTags()) {
copiedTags.add(tag);
}
}
Course courseCopy = new Course(
null, // copy has no id
name, // copy has new name
course.getCreated(),
course.getLastModified(),
description, // copy has new description
course.getArchived(),
course.getCourseNumber(),
course.getMaxParticipantCount(),
course.getBeginDate(),
course.getEndDate(),
nameExtension, // copy has new name extension
course.getLocalTeachingDays(),
course.getTeachingHours(),
course.getDistanceTeachingHours(),
course.getDistanceTeachingDays(),
course.getAssessingHours(),
course.getPlanningHours(),
course.getEnrolmentTimeEnd(),
course.getCreatorId(),
course.getLastModifierId(),
course.getSubjectId(),
course.getCurriculumIds(),
course.getLength(),
course.getLengthUnitId(),
course.getModuleId(),
course.getStateId(),
course.getTypeId(),
null, // variables are not copied
copiedTags); // copy has its own tag list
Course createdCourse = pyramusClient.post("/courses/courses/", courseCopy);
if (createdCourse == null) {
logger.severe(String.format("Failed to create new course based on course %d", pyramusCourseId));
return null;
}
// #2915: Copy additional course descriptions
CourseDescription[] courseDescriptions = pyramusClient.get(String.format("/courses/courses/%d/descriptions", pyramusCourseId), CourseDescription[].class);
if (ArrayUtils.isNotEmpty(courseDescriptions)) {
for (int i = 0; i < courseDescriptions.length; i++) {
pyramusClient.post(
String.format("/courses/courses/%d/descriptions", createdCourse.getId()),
new CourseDescription(
null,
createdCourse.getId(),
courseDescriptions[i].getCourseDescriptionCategoryId(),
courseDescriptions[i].getDescription()));
}
}
SchoolDataIdentifier workspaceIdentifier = new SchoolDataIdentifier(identifierMapper.getWorkspaceIdentifier(createdCourse.getId()), SchoolDataPyramusPluginDescriptor.SCHOOL_DATA_SOURCE);
workspaceDiscoveryWaiter.waitDiscovered(workspaceIdentifier);
return createWorkspaceEntity(createdCourse);
}
@Override
public Workspace findWorkspace(String identifier) {
Long pyramusCourseId = identifierMapper.getPyramusCourseId(identifier);
if (pyramusCourseId == null) {
logger.severe(String.format("Workspace identifier %s is not valid", identifier));
return null;
}
return createWorkspaceEntity(pyramusClient.get(String.format("/courses/courses/%d", pyramusCourseId), Course.class));
}
@Override
public List<Workspace> listWorkspaces() {
List<Workspace> result = new ArrayList<Workspace>();
Course[] courses = pyramusClient.get("/courses/courses/", Course[].class);
if (courses != null) {
for (Course course : courses) {
result.add(createWorkspaceEntity(course));
}
}
return result;
}
@Override
public List<Workspace> listWorkspacesByCourseIdentifier(String courseIdentifierIdentifier) {
if (courseIdentifierIdentifier.indexOf("/") == -1)
throw new SchoolDataBridgeInternalException("Invalid CourseIdentifierId");
String subjectId = courseIdentifierIdentifier.substring(0, courseIdentifierIdentifier.indexOf("/"));
String courseNumber = courseIdentifierIdentifier.substring(courseIdentifierIdentifier.indexOf("/") + 1);
Course[] courses = pyramusClient.get("/common/subjects/" + subjectId + "/courses", fi.otavanopisto.pyramus.rest.model.Course[].class);
List<Workspace> result = new ArrayList<Workspace>();
for (Course course : courses) {
String courseNumber2 = course.getCourseNumber() != null ? course.getCourseNumber().toString() : "null";
if (courseNumber.equals(courseNumber2))
result.add(createWorkspaceEntity(course));
}
return result;
}
@Override
public Workspace updateWorkspace(Workspace workspace) {
Long pyramusCourseId = identifierMapper.getPyramusCourseId(workspace.getIdentifier());
if (pyramusCourseId == null) {
logger.severe(String.format("Workspace identifier %s is not valid", workspace.getIdentifier()));
return null;
}
Long typeId = identifierMapper.getPyramusCourseTypeId(workspace.getWorkspaceTypeId());
Long lengthUnitId = identifierMapper.getPyramusEducationalTimeUnitId(workspace.getLengthUnitIdentifier());
Long subjectId = identifierMapper.getPyramusSubjectId(workspace.getSubjectIdentifier());
Course course = pyramusClient.get(String.format("/courses/courses/%d", pyramusCourseId), Course.class);
course.setName(workspace.getName());
course.setNameExtension(workspace.getNameExtension());
course.setDescription(workspace.getDescription());
course.setBeginDate(workspace.getBeginDate());
course.setEndDate(workspace.getEndDate());
course.setLength(workspace.getLength());
course.setLengthUnitId(lengthUnitId);
course.setTypeId(typeId);
course.setSubjectId(subjectId);
Course updatedCourse = pyramusClient.put(String.format("/courses/courses/%d", pyramusCourseId), course);
if (updatedCourse == null) {
logger.severe(String.format("Workspace %s updating failed", workspace.getIdentifier()));
return null;
}
return createWorkspaceEntity(updatedCourse);
}
@Override
public void removeWorkspace(String identifier) {
if (!StringUtils.isNumeric(identifier)) {
throw new SchoolDataBridgeInternalException("Identifier has to be numeric");
}
throw new SchoolDataBridgeInternalException("Not implemented");
}
@Override
public WorkspaceType findWorkspaceType(String identifier) {
if (identifier == null) {
return null;
}
if (!StringUtils.isNumeric(identifier)) {
throw new SchoolDataBridgeInternalException("Identifier has to be numeric");
}
return entityFactory.createEntity(pyramusClient.get("/courses/courseTypes/" + identifier, fi.otavanopisto.pyramus.rest.model.CourseType.class));
}
@Override
public List<WorkspaceType> listWorkspaceTypes() {
return entityFactory.createEntities(pyramusClient.get("/courses/courseTypes/", fi.otavanopisto.pyramus.rest.model.CourseType[].class));
}
@Override
public WorkspaceUser createWorkspaceUser(Workspace workspace, User user, String roleSchoolDataSource, String roleIdentifier) {
Long courseId = identifierMapper.getPyramusCourseId(workspace.getIdentifier());
Long studentId = identifierMapper.getPyramusStudentId(user.getIdentifier());
CourseStudent courseStudent = new CourseStudent(null, courseId, studentId, OffsetDateTime.now(), Boolean.FALSE, null, null, Boolean.FALSE, CourseOptionality.OPTIONAL, null);
return Arrays.asList(entityFactory.createEntity(pyramusClient.post("/courses/courses/" + courseId + "/students", courseStudent))).get(0);
}
@Override
public WorkspaceUser findWorkspaceUser(SchoolDataIdentifier workspaceIdentifier, SchoolDataIdentifier workspaceUserIdentifier) {
if (!StringUtils.equals(workspaceIdentifier.getDataSource(), getSchoolDataSource())) {
throw new SchoolDataBridgeInternalException("Invalid school data source");
}
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier.getIdentifier());
Long courseStudentId = identifierMapper.getPyramusCourseStudentId(workspaceUserIdentifier.getIdentifier());
return Arrays.asList(entityFactory.createEntity(pyramusClient.get(String.format("/courses/courses/%d/students/%d", courseId, courseStudentId), CourseStudent.class))).get(0);
}
@Override
public WorkspaceUser findWorkspaceUserByWorkspaceAndUser(SchoolDataIdentifier workspaceIdentifier, SchoolDataIdentifier userIdentifier) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier.getIdentifier());
Long userId = identifierMapper.getPyramusStudentId(userIdentifier.getIdentifier());
if (courseId != null && userId != null) {
List<WorkspaceUser> users = entityFactory.createEntity(pyramusClient.get(String.format("/courses/courses/%d/students?studentId=%d", courseId, userId), CourseStudent[].class));
if (users != null) {
if (users.size() > 1) {
logger.warning(String.format("Student %d appears %d times in course %d", userId, users.size(), courseId));
}
return users.isEmpty() ? null : users.get(0);
}
}
else {
logger.severe(String.format("null courseId %d or userId &d", courseId, userId));
}
return null;
}
@Override
public List<WorkspaceUser> listWorkspaceUsers(String workspaceIdentifier) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier);
CourseStaffMember[] staffMembers = pyramusClient.get("/courses/courses/" + courseId + "/staffMembers", CourseStaffMember[].class);
CourseStudent[] courseStudents = pyramusClient.get("/courses/courses/" + courseId + "/students", CourseStudent[].class);
List<WorkspaceUser> result = entityFactory.createEntity(staffMembers);
result.addAll(entityFactory.createEntity(courseStudents));
return result;
}
private Workspace createWorkspaceEntity(Course course) {
if (course == null)
return null;
SchoolDataIdentifier educationTypeIdentifier = null;
if (course.getSubjectId() != null) {
Subject subject = pyramusClient.get("/common/subjects/" + course.getSubjectId(), fi.otavanopisto.pyramus.rest.model.Subject.class);
if (subject == null) {
logger.severe(String.format("Subject with id %d not found", course.getSubjectId()));
}
else {
educationTypeIdentifier = identifierMapper.getEducationTypeIdentifier(subject.getEducationTypeId());
}
}
Map<String, List<String>> courseEducationTypeMap = new HashMap<String, List<String>>();
CourseEducationType[] courseEducationTypes = pyramusClient.get(
String.format("/courses/courses/%d/educationTypes", course.getId()),
CourseEducationType[].class);
if (courseEducationTypes != null ) {
for (CourseEducationType courseEducationType: courseEducationTypes) {
// #1632: if subject didn't determine education type and course only has one education type, use that instead
if (educationTypeIdentifier == null && courseEducationTypes.length == 1) {
educationTypeIdentifier = identifierMapper.getEducationTypeIdentifier(courseEducationTypes[0].getEducationTypeId());
}
CourseEducationSubtype[] courseEducationSubtypes = pyramusClient.get(
String.format("/courses/courses/%d/educationTypes/%d/educationSubtypes", course.getId(), courseEducationType.getId()),
CourseEducationSubtype[].class);
if (courseEducationSubtypes == null) {
continue;
}
EducationType educationType = pyramusClient.get(
String.format("/common/educationTypes/%d", courseEducationType.getEducationTypeId()),
EducationType.class);
if (educationType == null) {
logger.severe(String.format("Could not find educationType %d", courseEducationType.getEducationTypeId()));
continue;
}
String educationTypeCode = educationType.getCode();
List<String> courseEducationSubtypeList = new ArrayList<String>();
for (CourseEducationSubtype courseEducationSubtype : courseEducationSubtypes) {
EducationSubtype educationSubtype = pyramusClient.get(
String.format(
"/common/educationTypes/%d/subtypes/%d",
educationType.getId(),
courseEducationSubtype.getEducationSubtypeId()),
EducationSubtype.class);
if (educationSubtype != null) {
String educationSubtypeCode = educationSubtype.getCode();
courseEducationSubtypeList.add(educationSubtypeCode);
} else {
logger.severe(String.format("Could not find education subtype %d from type %d", courseEducationSubtype.getEducationSubtypeId(), educationType.getId()));
}
}
courseEducationTypeMap.put(educationTypeCode, courseEducationSubtypeList);
}
}
return entityFactory.createEntity(course, educationTypeIdentifier, courseEducationTypeMap);
}
@Override
public List<WorkspaceUser> listWorkspaceStaffMembers(String workspaceIdentifier) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier);
if (courseId != null) {
CourseStaffMember[] staffMembers = pyramusClient.get(String.format("/courses/courses/%d/staffMembers", courseId), CourseStaffMember[].class);
if (staffMembers != null) {
return entityFactory.createEntity(staffMembers);
}
}
return Collections.<WorkspaceUser>emptyList();
}
@Override
public List<WorkspaceUser> listWorkspaceStudents(String workspaceIdentifier) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier);
CourseStudent[] students = pyramusClient.get(String.format("/courses/courses/%d/students?activeStudents=true", courseId), CourseStudent[].class);
if (students != null) {
return entityFactory.createEntity(students);
}
return Collections.<WorkspaceUser>emptyList();
}
@Override
public List<WorkspaceUser> listWorkspaceStudents(String workspaceIdentifier, boolean active) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceIdentifier);
String participationTypes = active ? pyramusStudentActivityMapper.getActiveCDT() : pyramusStudentActivityMapper.getInactiveCDT();
if (StringUtils.isEmpty(participationTypes)) {
logger.warning(String.format("Undefined plugin setting:%s-participationTypes.workspace.(in)active", SchoolDataPyramusPluginDescriptor.PLUGIN_NAME));
}
else {
CourseStudent[] students = pyramusClient.get(String.format("/courses/courses/%d/students?participationTypes=%s", courseId, participationTypes), CourseStudent[].class);
if (students != null) {
return entityFactory.createEntity(students);
}
}
return Collections.<WorkspaceUser>emptyList();
}
@Override
public void updateWorkspaceStudentActivity(WorkspaceUser workspaceUser, boolean active) {
Long courseId = identifierMapper.getPyramusCourseId(workspaceUser.getWorkspaceIdentifier().getIdentifier());
Long courseStudentId = identifierMapper.getPyramusCourseStudentId(workspaceUser.getIdentifier().getIdentifier());
CourseStudent courseStudent = pyramusClient.get(String.format("/courses/courses/%d/students/%d", courseId, courseStudentId), CourseStudent.class);
if (courseStudent != null) {
Long currentParticipationType = courseStudent.getParticipationTypeId();
if (pyramusStudentActivityMapper.isActive(currentParticipationType) != active) {
Long newParticipationType = active ? pyramusStudentActivityMapper.toActive(currentParticipationType) : pyramusStudentActivityMapper.toInactive(currentParticipationType);
if (newParticipationType == null) {
newParticipationType = currentParticipationType;
}
CourseParticipationType participationType = pyramusClient.get(String.format("/courses/participationTypes/%d", newParticipationType), CourseParticipationType.class);
if (participationType != null) {
courseStudent.setParticipationTypeId(participationType.getId());
pyramusClient.put(String.format("/courses/courses/%d/students/%d", courseId, courseStudentId), courseStudent);
} else {
logger.warning(String.format("Could not find participation type %d", newParticipationType));
}
}
}
}
}