package fi.otavanopisto.muikku.rest.user;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.ejb.Stateful;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import fi.otavanopisto.muikku.model.users.EnvironmentRoleArchetype;
import fi.otavanopisto.muikku.model.users.EnvironmentRoleEntity;
import fi.otavanopisto.muikku.model.users.EnvironmentUser;
import fi.otavanopisto.muikku.model.users.Flag;
import fi.otavanopisto.muikku.model.users.FlagShare;
import fi.otavanopisto.muikku.model.users.FlagStudent;
import fi.otavanopisto.muikku.model.users.UserEntity;
import fi.otavanopisto.muikku.model.users.UserEntityProperty;
import fi.otavanopisto.muikku.model.users.UserGroupEntity;
import fi.otavanopisto.muikku.model.users.UserSchoolDataIdentifier;
import fi.otavanopisto.muikku.model.workspace.WorkspaceEntity;
import fi.otavanopisto.muikku.rest.AbstractRESTService;
import fi.otavanopisto.muikku.rest.RESTPermitUnimplemented;
import fi.otavanopisto.muikku.rest.model.Student;
import fi.otavanopisto.muikku.rest.model.StudentAddress;
import fi.otavanopisto.muikku.rest.model.StudentEmail;
import fi.otavanopisto.muikku.rest.model.StudentPhoneNumber;
import fi.otavanopisto.muikku.rest.model.UserBasicInfo;
import fi.otavanopisto.muikku.schooldata.GradingController;
import fi.otavanopisto.muikku.schooldata.RestCatchSchoolDataExceptions;
import fi.otavanopisto.muikku.schooldata.SchoolDataBridgeSessionController;
import fi.otavanopisto.muikku.schooldata.SchoolDataIdentifier;
import fi.otavanopisto.muikku.schooldata.entity.TransferCredit;
import fi.otavanopisto.muikku.schooldata.entity.User;
import fi.otavanopisto.muikku.schooldata.entity.UserAddress;
import fi.otavanopisto.muikku.schooldata.entity.UserEmail;
import fi.otavanopisto.muikku.schooldata.entity.UserPhoneNumber;
import fi.otavanopisto.muikku.search.SearchProvider;
import fi.otavanopisto.muikku.search.SearchResult;
import fi.otavanopisto.muikku.security.MuikkuPermissions;
import fi.otavanopisto.muikku.security.RoleFeatures;
import fi.otavanopisto.muikku.session.SessionController;
import fi.otavanopisto.muikku.users.EnvironmentUserController;
import fi.otavanopisto.muikku.users.FlagController;
import fi.otavanopisto.muikku.users.UserController;
import fi.otavanopisto.muikku.users.UserEmailEntityController;
import fi.otavanopisto.muikku.users.UserEntityController;
import fi.otavanopisto.muikku.users.UserGroupEntityController;
import fi.otavanopisto.muikku.users.UserSchoolDataIdentifierController;
import fi.otavanopisto.muikku.users.WorkspaceUserEntityController;
import fi.otavanopisto.security.rest.RESTPermit;
import fi.otavanopisto.security.rest.RESTPermit.Handling;
@Stateful
@RequestScoped
@Path("/user")
@Produces("application/json")
@Consumes("application/json")
@RestCatchSchoolDataExceptions
public class UserRESTService extends AbstractRESTService {
@Inject
private Logger logger;
@Inject
private UserController userController;
@Inject
private UserEntityController userEntityController;
@Inject
private EnvironmentUserController environmentUserController;
@Inject
private UserGroupEntityController userGroupEntityController;
@Inject
private UserEmailEntityController userEmailEntityController;
@Inject
private SessionController sessionController;
@Inject
private SchoolDataBridgeSessionController schoolDataBridgeSessionController;
@Inject
private WorkspaceUserEntityController workspaceUserEntityController;
@Inject
private FlagController flagController;
@Inject
private UserSchoolDataIdentifierController userSchoolDataIdentifierController;
@Inject
private GradingController gradingController;
@Inject
@Any
private Instance<SearchProvider> searchProviders;
@GET
@Path("/property/{KEY}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response getUserEntityProperty(@PathParam("KEY") String key) {
UserEntity loggedUserEntity = sessionController.getLoggedUserEntity();
UserEntityProperty property = userEntityController.getUserEntityPropertyByKey(loggedUserEntity, key);
return Response.ok(new fi.otavanopisto.muikku.rest.model.UserEntityProperty(key, property == null ? null : property.getValue())).build();
}
@GET
@Path("/properties/{USERENTITYID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response getUserEntityProperties(@PathParam("USERENTITYID") Long userEntityId, @QueryParam("properties") String keys) {
// TODO Security (maybe via visibility in userEntityProperty?)
UserEntity userEntity = userEntityController.findUserEntityById(userEntityId);
if (userEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
List<UserEntityProperty> storedProperties = new ArrayList<UserEntityProperty>();
List<fi.otavanopisto.muikku.rest.model.UserEntityProperty> restProperties = new ArrayList<fi.otavanopisto.muikku.rest.model.UserEntityProperty>();
if (StringUtils.isBlank(keys)) {
storedProperties = userEntityController.listUserEntityProperties(userEntity);
for (UserEntityProperty property : storedProperties) {
restProperties.add(new fi.otavanopisto.muikku.rest.model.UserEntityProperty(property.getKey(), property.getValue()));
}
}
else {
UserEntityProperty storedProperty;
String[] keyArray = keys.split(",");
for (int i = 0; i < keyArray.length; i++) {
storedProperty = userEntityController.getUserEntityPropertyByKey(userEntity, keyArray[i]);
String value = storedProperty == null ? null : storedProperty.getValue();
restProperties.add(new fi.otavanopisto.muikku.rest.model.UserEntityProperty(keyArray[i], value));
}
}
return Response.ok(restProperties).build();
}
@POST
@Path("/property")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response setUserEntityProperty(fi.otavanopisto.muikku.rest.model.UserEntityProperty payload) {
UserEntity loggedUserEntity = sessionController.getLoggedUserEntity();
userEntityController.setUserEntityProperty(loggedUserEntity, payload.getKey(), payload.getValue());
return Response.ok(payload).build();
}
@GET
@Path("/students")
@RESTPermit (handling = Handling.INLINE)
public Response searchStudents(
@QueryParam("searchString") String searchString,
@QueryParam("firstResult") @DefaultValue("0") Integer firstResult,
@QueryParam("maxResults") @DefaultValue("10") Integer maxResults,
@QueryParam("userGroupIds") List<Long> userGroupIds,
@QueryParam("myUserGroups") Boolean myUserGroups,
@QueryParam("workspaceIds") List<Long> workspaceIds,
@QueryParam("myWorkspaces") Boolean myWorkspaces,
@QueryParam("userEntityId") Long userEntityId,
@DefaultValue ("false") @QueryParam("includeInactiveStudents") Boolean includeInactiveStudents,
@DefaultValue ("false") @QueryParam("includeHidden") Boolean includeHidden,
@QueryParam("flags") Long[] flagIds) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
if (CollectionUtils.isNotEmpty(userGroupIds) && Boolean.TRUE.equals(myUserGroups)) {
return Response.status(Status.BAD_REQUEST).build();
}
if (CollectionUtils.isNotEmpty(workspaceIds) && Boolean.TRUE.equals(myWorkspaces)) {
return Response.status(Status.BAD_REQUEST).build();
}
List<Flag> flags = null;
if (flagIds != null && flagIds.length > 0) {
flags = new ArrayList<>(flagIds.length);
for (Long flagId : flagIds) {
Flag flag = flagController.findFlagById(flagId);
if (flag == null) {
return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid flag id %d", flagId)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You don't have permission to use flag %d", flagId)).build();
}
flags.add(flag);
}
}
List<fi.otavanopisto.muikku.rest.model.Student> students = new ArrayList<>();
UserEntity loggedUser = sessionController.getLoggedUserEntity();
Set<Long> userGroupFilters = null;
Set<Long> workspaceFilters = null;
if (!sessionController.hasEnvironmentPermission(RoleFeatures.ACCESS_ONLY_GROUP_STUDENTS)) {
if ((myUserGroups != null) && myUserGroups) {
userGroupFilters = new HashSet<Long>();
// Groups where user is a member
List<UserGroupEntity> userGroups = userGroupEntityController.listUserGroupsByUserIdentifier(sessionController.getLoggedUser());
for (UserGroupEntity userGroup : userGroups) {
userGroupFilters.add(userGroup.getId());
}
} else if (!CollectionUtils.isEmpty(userGroupIds)) {
userGroupFilters = new HashSet<Long>();
// Defined user groups
userGroupFilters.addAll(userGroupIds);
}
} else {
// User can only list users from his/her own user groups
userGroupFilters = new HashSet<Long>();
// Groups where user is a member and the ids of the groups
List<UserGroupEntity> userGroups = userGroupEntityController.listUserGroupsByUserIdentifier(sessionController.getLoggedUser());
Set<Long> accessibleUserGroupEntityIds = userGroups.stream().map(UserGroupEntity::getId).collect(Collectors.toSet());
if (CollectionUtils.isNotEmpty(userGroupIds)) {
// if there are specified user groups, they need to be subset of the groups that the user can access
if (!CollectionUtils.isSubCollection(userGroupIds, accessibleUserGroupEntityIds))
return Response.status(Status.BAD_REQUEST).build();
userGroupFilters.addAll(userGroupIds);
} else {
userGroupFilters.addAll(accessibleUserGroupEntityIds);
}
}
List<SchoolDataIdentifier> userIdentifiers = null;
if (flags != null) {
if (userIdentifiers == null) {
userIdentifiers = new ArrayList<>();
}
userIdentifiers.addAll(flagController.getFlaggedStudents(flags));
}
if (Boolean.TRUE.equals(includeInactiveStudents)) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_INACTIVE_STUDENTS)) {
if (userEntityId == null) {
return Response.status(Status.FORBIDDEN).build();
} else {
if (!sessionController.getLoggedUserEntity().getId().equals(userEntityId)) {
return Response.status(Status.FORBIDDEN).build();
}
}
}
}
if (Boolean.TRUE.equals(includeHidden)) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_HIDDEN_STUDENTS)) {
if (userEntityId == null) {
return Response.status(Status.FORBIDDEN).build();
} else {
if (!sessionController.getLoggedUserEntity().getId().equals(userEntityId)) {
return Response.status(Status.FORBIDDEN).build();
}
}
}
}
if (userEntityId != null) {
List<SchoolDataIdentifier> userEntityIdentifiers = new ArrayList<>();
UserEntity userEntity = userEntityController.findUserEntityById(userEntityId);
if (userEntity == null) {
return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid userEntityId %d", userEntityId)).build();
}
List<UserSchoolDataIdentifier> schoolDataIdentifiers = userSchoolDataIdentifierController.listUserSchoolDataIdentifiersByUserEntity(userEntity);
for (UserSchoolDataIdentifier schoolDataIdentifier : schoolDataIdentifiers) {
userEntityIdentifiers.add(new SchoolDataIdentifier(schoolDataIdentifier.getIdentifier(), schoolDataIdentifier.getDataSource().getIdentifier()));
}
if (userIdentifiers == null) {
userIdentifiers = userEntityIdentifiers;
} else {
userIdentifiers.retainAll(userEntityIdentifiers);
}
}
if ((myWorkspaces != null) && myWorkspaces) {
// Workspaces where user is a member
List<WorkspaceEntity> workspaces = workspaceUserEntityController.listWorkspaceEntitiesByUserEntity(loggedUser);
Set<Long> myWorkspaceIds = new HashSet<Long>();
for (WorkspaceEntity ws : workspaces)
myWorkspaceIds.add(ws.getId());
workspaceFilters = new HashSet<>(myWorkspaceIds);
} else if (!CollectionUtils.isEmpty(workspaceIds)) {
// Defined workspaces
workspaceFilters = new HashSet<>(workspaceIds);
}
SearchProvider elasticSearchProvider = getProvider("elastic-search");
if (elasticSearchProvider != null) {
String[] fields = new String[] { "firstName", "lastName", "nickName" };
SearchResult result = elasticSearchProvider.searchUsers(searchString, fields, Arrays.asList(EnvironmentRoleArchetype.STUDENT),
userGroupFilters, workspaceFilters, userIdentifiers, includeInactiveStudents, includeHidden, false, firstResult, maxResults);
List<Map<String, Object>> results = result.getResults();
boolean hasImage = false;
if (results != null && !results.isEmpty()) {
for (Map<String, Object> o : results) {
String studentId = (String) o.get("id");
if (StringUtils.isBlank(studentId)) {
logger.severe("Could not process user found from search index because it had a null id");
continue;
}
String[] studentIdParts = studentId.split("/", 2);
SchoolDataIdentifier studentIdentifier = studentIdParts.length == 2 ? new SchoolDataIdentifier(studentIdParts[0], studentIdParts[1]) : null;
if (studentIdentifier == null) {
logger.severe(String.format("Could not process user found from search index with id %s", studentId));
continue;
}
UserEntity userEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
String emailAddress = userEntity != null ? userEmailEntityController.getUserDefaultEmailAddress(userEntity, true) : null;
Date studyStartDate = getDateResult(o.get("studyStartDate"));
Date studyEndDate = getDateResult(o.get("studyEndDate"));
Date studyTimeEnd = getDateResult(o.get("studyTimeEnd"));
students.add(new fi.otavanopisto.muikku.rest.model.Student(
studentIdentifier.toId(),
(String) o.get("firstName"),
(String) o.get("lastName"),
(String) o.get("nickName"),
(String) o.get("studyProgrammeName"),
hasImage,
(String) o.get("nationality"),
(String) o.get("language"),
(String) o.get("municipality"),
(String) o.get("school"),
emailAddress,
studyStartDate,
studyEndDate,
studyTimeEnd,
(String) o.get("curriculumIdentifier"),
userEntity.getUpdatedByStudent()));
}
}
}
return Response.ok(students).build();
}
private Date getDateResult(Object value) {
if (value instanceof Long) {
return new Date((Long) value);
}
return null;
}
@GET
@Path("/students/{ID}")
@RESTPermit (handling = Handling.INLINE)
public Response findStudent(@Context Request request, @PathParam("ID") String id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity userEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (userEntity == null) {
return Response.status(Status.NOT_FOUND).entity("UserEntity not found").build();
}
// Bug fix #2966: REST endpoint should only return students
EnvironmentUser environmentUser = environmentUserController.findEnvironmentUserByUserEntity(userEntity);
if (environmentUser != null) {
EnvironmentRoleEntity userRole = environmentUser.getRole();
if (userRole == null || userRole.getArchetype() != EnvironmentRoleArchetype.STUDENT) {
return Response.status(Status.NOT_FOUND).build();
}
}
EntityTag tag = new EntityTag(DigestUtils.md5Hex(String.valueOf(userEntity.getVersion())));
ResponseBuilder builder = request.evaluatePreconditions(tag);
if (builder != null) {
return builder.build();
}
CacheControl cacheControl = new CacheControl();
cacheControl.setMustRevalidate(true);
// TODO: There's no permission handling, this is relying on schooldatacontroller to check for permission
User user = userController.findUserByIdentifier(studentIdentifier);
if (user == null) {
return Response.status(Status.NOT_FOUND).entity("User not found").build();
}
String emailAddress = userEmailEntityController.getUserDefaultEmailAddress(userEntity, true);
Date studyStartDate = user.getStudyStartDate() != null ? Date.from(user.getStudyStartDate().toInstant()) : null;
Date studyEndDate = user.getStudyEndDate() != null ? Date.from(user.getStudyEndDate().toInstant()) : null;
Date studyTimeEnd = user.getStudyTimeEnd() != null ? Date.from(user.getStudyTimeEnd().toInstant()) : null;
Student student = new Student(
studentIdentifier.toId(),
user.getFirstName(),
user.getLastName(),
user.getNickName(),
user.getStudyProgrammeName(),
false,
user.getNationality(),
user.getLanguage(),
user.getMunicipality(),
user.getSchool(),
emailAddress,
studyStartDate,
studyEndDate,
studyTimeEnd,
user.getCurriculumIdentifier(),
userEntity.getUpdatedByStudent());
return Response
.ok(student)
.cacheControl(cacheControl)
.tag(tag)
.build();
}
@PUT
@Path("/students/{ID}")
@RESTPermit (handling = Handling.INLINE)
public Response updateStudent(
@PathParam("ID") String id,
Student student) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
SchoolDataIdentifier loggedUserIdentifier = sessionController.getLoggedUser();
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
if (!(Objects.equals(studentIdentifier.getIdentifier(), loggedUserIdentifier.getIdentifier()) &&
Objects.equals(studentIdentifier.getDataSource(), loggedUserIdentifier.getDataSource()))) {
return Response.status(Status.FORBIDDEN).entity("Trying to modify non-logged-in student").build();
}
User user = userController.findUserByIdentifier(studentIdentifier);
UserEntity userEntity = userEntityController.findUserEntityByUser(user);
userEntityController.markAsUpdatedByStudent(userEntity);
// TODO: update other fields too
user.setMunicipality(student.getMunicipality());
userController.updateUser(user);
return Response.ok().entity(student).build();
}
@GET
@Path("/students/{ID}/flags")
@RESTPermit (handling = Handling.INLINE)
public Response listStudentFlags(@Context Request request, @PathParam("ID") String id, @QueryParam("ownerIdentifier") String ownerId) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
if (StringUtils.isBlank(ownerId)) {
return Response.status(Response.Status.NOT_IMPLEMENTED).entity("Listing student flags without owner is not implemented").build();
}
SchoolDataIdentifier ownerIdentifier = SchoolDataIdentifier.fromId(ownerId);
if (ownerIdentifier == null) {
return Response.status(Status.BAD_REQUEST).entity("ownerIdentifier is malformed").build();
}
if (!ownerIdentifier.equals(sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).build();
}
List<FlagStudent> flags = flagController.listByOwnedAndSharedStudentFlags(studentIdentifier, ownerIdentifier);
return Response.ok(createRestModel(flags.toArray(new FlagStudent[0]))).build();
}
@POST
@Path("/students/{ID}/flags")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response createStudentFlag(@Context Request request, @PathParam("ID") String id, fi.otavanopisto.muikku.rest.model.StudentFlag payload) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
if (payload.getFlagId() == null) {
return Response.status(Response.Status.BAD_REQUEST).entity("Missing flagId").build();
}
Flag flag = flagController.findFlagById(payload.getFlagId());
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag #%d not found", payload.getFlagId())).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag students to flag %d", payload.getFlagId())).build();
}
return Response.ok(createRestModel(flagController.flagStudent(flag, studentIdentifier))).build();
}
@DELETE
@Path("/students/{STUDENTID}/flags/{ID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response deleteStudentFlag(@Context Request request, @PathParam("STUDENTID") String studentId, @PathParam("ID") Long id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(studentId);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", studentId)).build();
}
FlagStudent flagStudent = flagController.findFlagStudentById(id);
if (flagStudent == null) {
return Response.status(Response.Status.NOT_FOUND).entity(String.format("Flag not found %d", id)).build();
}
if (!flagController.hasFlagPermission(flagStudent.getFlag(), sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to remove student flag %d", flagStudent.getId())).build();
}
flagController.unflagStudent(flagStudent);
return Response.noContent().build();
}
@GET
@Path("/students/{ID}/phoneNumbers")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listStudentPhoneNumbers(@PathParam("ID") String id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (studentEntity == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Could not find user entity for identifier %s", id)).build();
}
if (!studentEntity.getId().equals(sessionController.getLoggedUserEntity().getId())) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_STUDENT_PHONE_NUMBERS)) {
return Response.status(Status.FORBIDDEN).build();
}
}
List<UserPhoneNumber> phoneNumbers = userController.listUserPhoneNumbers(studentIdentifier);
Collections.sort(phoneNumbers, new Comparator<UserPhoneNumber>() {
@Override
public int compare(UserPhoneNumber o1, UserPhoneNumber o2) {
return o1.getDefaultNumber() ? -1 : o2.getDefaultNumber() ? 1 : 0;
}
});
return Response.ok(createRestModel(phoneNumbers.toArray(new UserPhoneNumber[0]))).build();
}
@GET
@Path("/students/{ID}/emails")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listStudentEmails(@PathParam("ID") String id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (studentEntity == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Could not find user entity for identifier %s", id)).build();
}
if (!studentEntity.getId().equals(sessionController.getLoggedUserEntity().getId())) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_STUDENT_EMAILS)) {
return Response.status(Status.FORBIDDEN).build();
}
}
List<UserEmail> emails = userController.listUserEmails(studentIdentifier);
Collections.sort(emails, new Comparator<UserEmail>() {
@Override
public int compare(UserEmail o1, UserEmail o2) {
return o1.getDefaultAddress() ? -1 : o2.getDefaultAddress() ? 1 : 0;
}
});
return Response.ok(createRestModel(emails.toArray(new UserEmail[0]))).build();
}
@GET
@Path("/students/{ID}/addresses")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listStudentAddressses(@PathParam("ID") String id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (studentEntity == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Could not find user entity for identifier %s", id)).build();
}
if (!studentEntity.getId().equals(sessionController.getLoggedUserEntity().getId())) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_STUDENT_ADDRESSES)) {
return Response.status(Status.FORBIDDEN).build();
}
}
List<UserAddress> addresses = userController.listUserAddresses(studentIdentifier);
Collections.sort(addresses, new Comparator<UserAddress>() {
@Override
public int compare(UserAddress o1, UserAddress o2) {
return o1.getDefaultAddress() ? -1 : o2.getDefaultAddress() ? 1 : 0;
}
});
return Response.ok(createRestModel(addresses.toArray(new UserAddress[0]))).build();
}
@PUT
@Path("/students/{ID}/addresses/{ADDRESSID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response updateStudentAddress(
@PathParam("ID") String id,
@PathParam("ADDRESSID") String addressId,
StudentAddress studentAddress
) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (studentEntity == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Could not find user entity for identifier %s", id)).build();
}
if (!studentEntity.getId().equals(sessionController.getLoggedUserEntity().getId())) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_STUDENT_ADDRESSES)) {
return Response.status(Status.FORBIDDEN).build();
}
}
List<UserAddress> addresses = userController.listUserAddresses(studentIdentifier);
for (UserAddress address : addresses) {
if (address.getIdentifier().toId().equals(studentAddress.getIdentifier())) {
userEntityController.markAsUpdatedByStudent(studentEntity);
userController.updateUserAddress(
studentIdentifier,
address.getIdentifier(),
studentAddress.getStreet(),
studentAddress.getPostalCode(),
studentAddress.getCity(),
studentAddress.getCountry());
return Response.ok().entity(studentAddress).build();
}
}
return Response.status(Status.NOT_FOUND).entity("address not found").build();
}
@GET
@Path("/students/{ID}/transferCredits")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response searchStudentTransferCredits(
@PathParam("ID") String id,
@QueryParam("curriculumEmpty") @DefaultValue ("true") Boolean curriculumEmpty,
@QueryParam("curriculumIdentifier") String curriculumIdentifier
) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(id);
if (studentIdentifier == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid studentIdentifier %s", id)).build();
}
UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier);
if (studentEntity == null) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Could not find user entity for identifier %s", id)).build();
}
if (!studentEntity.getId().equals(sessionController.getLoggedUserEntity().getId())) {
if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_STUDENT_TRANSFER_CREDITS)) {
return Response.status(Status.FORBIDDEN).build();
}
}
List<TransferCredit> transferCredits = new ArrayList<TransferCredit>(gradingController.listStudentTransferCredits(studentIdentifier));
for (int i = transferCredits.size() - 1; i >= 0; i--) {
TransferCredit tc = transferCredits.get(i);
SchoolDataIdentifier tcCurriculum = tc.getCurriculumIdentifier();
if (tcCurriculum != null) {
if (!StringUtils.isEmpty(curriculumIdentifier) && !Objects.equals(tcCurriculum.toId(), curriculumIdentifier)) {
transferCredits.remove(i);
}
} else {
if (!curriculumEmpty)
transferCredits.remove(i);
}
}
return Response.ok(createRestModel(transferCredits.toArray(new TransferCredit[0]))).build();
}
@POST
@Path("/flags/")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response createFlag(fi.otavanopisto.muikku.rest.model.Flag payload) {
if (StringUtils.isBlank(payload.getOwnerIdentifier())) {
return Response.status(Status.BAD_REQUEST).entity("ownerIdentifier is missing").build();
}
if (StringUtils.isBlank(payload.getColor())) {
return Response.status(Status.BAD_REQUEST).entity("color is missing").build();
}
if (StringUtils.isBlank(payload.getName())) {
return Response.status(Status.BAD_REQUEST).entity("name is missing").build();
}
SchoolDataIdentifier ownerIdentifier = SchoolDataIdentifier.fromId(payload.getOwnerIdentifier());
if (ownerIdentifier == null) {
return Response.status(Status.BAD_REQUEST).entity("ownerIdentifier is malformed").build();
}
Flag flag = flagController.createFlag(ownerIdentifier, payload.getName(), payload.getColor(), payload.getDescription());
return Response.ok(createRestModel(flag)).build();
}
@GET
@Path("/flags/")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listFlags(@QueryParam("ownerIdentifier") String ownerId) {
SchoolDataIdentifier ownerIdentifier = null;
if (StringUtils.isNotBlank(ownerId)) {
ownerIdentifier = SchoolDataIdentifier.fromId(ownerId);
if (ownerIdentifier == null) {
return Response.status(Status.BAD_REQUEST).entity("ownerIdentifier is malformed").build();
}
// TODO: Add permission to list flags owned by others
if (!ownerIdentifier.equals(sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).build();
}
} else {
return Response.status(Status.FORBIDDEN).build();
}
List<Flag> flags = flagController.listByOwnedAndSharedFlags(ownerIdentifier);
return Response.ok(createRestModel(flags.toArray(new Flag[0]))).build();
}
@GET
@Path("/flags/{ID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listFlags(@PathParam ("ID") Long id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
Flag flag = flagController.findFlagById(id);
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (flag.getArchived()) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag#%d", flag.getId())).build();
}
return Response.ok(createRestModel(flag)).build();
}
@PUT
@Path("/flags/{ID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response updateFlag(@PathParam ("ID") Long id, fi.otavanopisto.muikku.rest.model.Flag payload) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
Flag flag = flagController.findFlagById(id);
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (flag.getArchived()) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag#%d", flag.getId())).build();
}
if (StringUtils.isBlank(payload.getColor())) {
return Response.status(Status.BAD_REQUEST).entity("color is missing").build();
}
if (StringUtils.isBlank(payload.getName())) {
return Response.status(Status.BAD_REQUEST).entity("name is missing").build();
}
return Response.ok(createRestModel(flagController.updateFlag(flag, payload.getName(), payload.getColor(), payload.getDescription()))).build();
}
@DELETE
@Path("/flags/{ID}")
@RESTPermit(handling = Handling.INLINE, requireLoggedIn = true)
public Response deleteFlag(@PathParam("ID") long flagId) {
Flag flag = flagController.findFlagById(flagId);
if (flag == null) {
return Response.status(Status.NOT_FOUND).build();
}
boolean isOwner = false;
UserSchoolDataIdentifier ownerIdentifier = flag.getOwnerIdentifier();
SchoolDataIdentifier loggedIdentifier = sessionController.getLoggedUser();
if (loggedIdentifier == null) {
return Response.status(Status.BAD_REQUEST).entity("Must be logged in.").build();
}
UserSchoolDataIdentifier loggedUserIdentifier =
userSchoolDataIdentifierController.findUserSchoolDataIdentifierBySchoolDataIdentifier(
loggedIdentifier);
if (loggedUserIdentifier == null) {
return Response
.status(Status.BAD_REQUEST)
.entity("No user school data identifier for logged user")
.build();
}
if (Objects.equals(ownerIdentifier.getIdentifier(), loggedUserIdentifier.getIdentifier()) &&
Objects.equals(ownerIdentifier.getDataSource().getIdentifier(),
loggedUserIdentifier.getDataSource().getIdentifier())) {
isOwner = true;
}
if (!flagController.hasFlagPermission(flag, loggedIdentifier)) {
return Response
.status(Status.FORBIDDEN)
.entity("You don't have the permission to delete this flag")
.build();
}
if (isOwner) {
flagController.deleteFlagCascade(flag);
return Response.noContent().build();
} else {
flagController.unshareFlag(flag, loggedUserIdentifier);
return Response.noContent().build();
}
}
@POST
@Path("/flags/{ID}/shares")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response createFlagShare(@PathParam ("ID") Long id, fi.otavanopisto.muikku.rest.model.FlagShare payload) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
Flag flag = flagController.findFlagById(id);
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (flag.getArchived()) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag#%d", flag.getId())).build();
}
SchoolDataIdentifier userIdentifier = SchoolDataIdentifier.fromId(payload.getUserIdentifier());
if (userIdentifier == null) {
return Response.status(Status.BAD_REQUEST).entity("userIdentifier is malformed").build();
}
return Response.ok(createRestModel(flagController.createFlagShare(flag, userIdentifier))).build();
}
@GET
@Path("/flags/{ID}/shares")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response listFlagShares(@PathParam ("ID") Long id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
Flag flag = flagController.findFlagById(id);
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (flag.getArchived()) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag#%d", flag.getId())).build();
}
return Response.ok(createRestModel(flagController.listShares(flag).toArray(new FlagShare[0]))).build();
}
@DELETE
@Path("/flags/{FLAGID}/shares/{ID}")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response createFlagShare(@PathParam ("FLAGID") Long flagId, @PathParam ("ID") Long id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.UNAUTHORIZED).build();
}
Flag flag = flagController.findFlagById(flagId);
if (flag == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (flag.getArchived()) {
return Response.status(Status.NOT_FOUND).entity(String.format("Flag#%d not found", id)).build();
}
if (!flagController.hasFlagPermission(flag, sessionController.getLoggedUser())) {
return Response.status(Status.FORBIDDEN).entity(String.format("You do not have permission to flag#%d", flag.getId())).build();
}
FlagShare flagShare = flagController.findFlagShare(id);
if (flagShare == null) {
return Response.status(Status.NOT_FOUND).entity(String.format("Could not find flag share %d", id)).build();
}
flagController.deleteFlagShare(flagShare);
return Response.noContent().build();
}
@GET
@Path("/users")
@RESTPermitUnimplemented
public Response searchUsers(
@QueryParam("searchString") String searchString,
@QueryParam("firstResult") @DefaultValue("0") Integer firstResult,
@QueryParam("maxResults") @DefaultValue("10") Integer maxResults,
@QueryParam("userGroupIds") List<Long> userGroupIds,
@QueryParam("myUserGroups") Boolean myUserGroups,
@QueryParam("workspaceIds") List<Long> workspaceIds,
@QueryParam("myWorkspaces") Boolean myWorkspaces,
@QueryParam("archetype") String archetype,
@DefaultValue ("false") @QueryParam("onlyDefaultUsers") Boolean onlyDefaultUsers) {
// TODO: Add new endpoint for listing staff members and deprecate this.
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
if (CollectionUtils.isNotEmpty(userGroupIds) && Boolean.TRUE.equals(myUserGroups))
return Response.status(Status.BAD_REQUEST).build();
if (CollectionUtils.isNotEmpty(workspaceIds) && Boolean.TRUE.equals(myWorkspaces))
return Response.status(Status.BAD_REQUEST).build();
UserEntity loggedUser = sessionController.getLoggedUserEntity();
EnvironmentRoleArchetype roleArchetype = archetype != null ? EnvironmentRoleArchetype.valueOf(archetype) : null;
Set<Long> userGroupFilters = null;
Set<Long> workspaceFilters = null;
if (!sessionController.hasEnvironmentPermission(RoleFeatures.ACCESS_ONLY_GROUP_STUDENTS)) {
if ((myUserGroups != null) && myUserGroups) {
userGroupFilters = new HashSet<Long>();
// Groups where user is a member
List<UserGroupEntity> userGroups = userGroupEntityController.listUserGroupsByUserIdentifier(sessionController.getLoggedUser());
for (UserGroupEntity userGroup : userGroups) {
userGroupFilters.add(userGroup.getId());
}
} else if (!CollectionUtils.isEmpty(userGroupIds)) {
userGroupFilters = new HashSet<Long>();
// Defined user groups
userGroupFilters.addAll(userGroupIds);
}
} else {
// User can only list users from his/her own user groups
userGroupFilters = new HashSet<Long>();
// Groups where user is a member and the ids of the groups
List<UserGroupEntity> userGroups = userGroupEntityController.listUserGroupsByUserIdentifier(sessionController.getLoggedUser());
Set<Long> accessibleUserGroupEntityIds = userGroups.stream().map(UserGroupEntity::getId).collect(Collectors.toSet());
if (CollectionUtils.isNotEmpty(userGroupIds)) {
// if there are specified user groups, they need to be subset of the groups that the user can access
if (!CollectionUtils.isSubCollection(userGroupIds, accessibleUserGroupEntityIds))
return Response.status(Status.BAD_REQUEST).build();
userGroupFilters.addAll(userGroupIds);
} else {
userGroupFilters.addAll(accessibleUserGroupEntityIds);
}
}
if ((myWorkspaces != null) && myWorkspaces) {
// Workspaces where user is a member
List<WorkspaceEntity> workspaces = workspaceUserEntityController.listWorkspaceEntitiesByUserEntity(loggedUser);
Set<Long> myWorkspaceIds = new HashSet<Long>();
for (WorkspaceEntity ws : workspaces)
myWorkspaceIds.add(ws.getId());
workspaceFilters = new HashSet<Long>(myWorkspaceIds);
} else if (!CollectionUtils.isEmpty(workspaceIds)) {
// Defined workspaces
workspaceFilters = new HashSet<Long>(workspaceIds);
}
SearchProvider elasticSearchProvider = getProvider("elastic-search");
if (elasticSearchProvider != null) {
String[] fields = new String[] { "firstName", "lastName", "nickName" };
SearchResult result = elasticSearchProvider.searchUsers(searchString,
fields,
roleArchetype != null ? Arrays.asList(roleArchetype) : null,
userGroupFilters,
workspaceFilters,
null,
false,
false,
onlyDefaultUsers,
firstResult,
maxResults);
List<Map<String, Object>> results = result.getResults();
boolean hasImage = false;
List<fi.otavanopisto.muikku.rest.model.User> ret = new ArrayList<fi.otavanopisto.muikku.rest.model.User>();
if (!results.isEmpty()) {
for (Map<String, Object> o : results) {
String[] id = ((String) o.get("id")).split("/", 2);
UserEntity userEntity = userEntityController
.findUserEntityByDataSourceAndIdentifier(id[1], id[0]);
if (userEntity != null) {
String emailAddress = userEmailEntityController.getUserDefaultEmailAddress(userEntity, true);
Date studyStartDate = getDateResult(o.get("studyStartDate"));
Date studyTimeEnd = getDateResult(o.get("studyTimeEnd"));
ret.add(new fi.otavanopisto.muikku.rest.model.User(
userEntity.getId(),
(String) o.get("firstName"),
(String) o.get("lastName"),
(String) o.get("nickName"),
hasImage,
(String) o.get("nationality"),
(String) o.get("language"),
(String) o.get("municipality"),
(String) o.get("school"),
emailAddress,
studyStartDate,
studyTimeEnd));
}
}
return Response.ok(ret).build();
} else
return Response.noContent().build();
}
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
@GET
@Path("/users/{ID}")
@RESTPermitUnimplemented
public Response findUser(@Context Request request, @PathParam("ID") Long id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
UserEntity userEntity = userEntityController.findUserEntityById(id);
if (userEntity == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
EntityTag tag = new EntityTag(DigestUtils.md5Hex(String.valueOf(userEntity.getVersion())));
ResponseBuilder builder = request.evaluatePreconditions(tag);
if (builder != null) {
return builder.build();
}
CacheControl cacheControl = new CacheControl();
cacheControl.setMustRevalidate(true);
User user = userController.findUserByDataSourceAndIdentifier(
userEntity.getDefaultSchoolDataSource(),
userEntity.getDefaultIdentifier());
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response
.ok(createRestModel(userEntity, user))
.cacheControl(cacheControl)
.tag(tag)
.build();
}
@GET
@Path("/users/{ID}/basicinfo")
@RESTPermitUnimplemented
public Response findUserBasicInfo(@Context Request request, @PathParam("ID") String id) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
UserEntity userEntity = null;
SchoolDataIdentifier userIdentifier = SchoolDataIdentifier.fromId(id);
if (userIdentifier == null) {
if (!StringUtils.isNumeric(id)) {
return Response.status(Response.Status.BAD_REQUEST).entity(String.format("Invalid user id %s", id)).build();
}
userEntity = userEntityController.findUserEntityById(NumberUtils.createLong(id));
userIdentifier = new SchoolDataIdentifier(userEntity.getDefaultIdentifier(), userEntity.getDefaultSchoolDataSource().getIdentifier());
} else {
userEntity = userEntityController.findUserEntityByUserIdentifier(userIdentifier);
}
if (userEntity == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
EntityTag tag = new EntityTag(DigestUtils.md5Hex(String.valueOf(userEntity.getVersion())));
ResponseBuilder builder = request.evaluatePreconditions(tag);
if (builder != null) {
return builder.build();
}
CacheControl cacheControl = new CacheControl();
cacheControl.setMustRevalidate(true);
schoolDataBridgeSessionController.startSystemSession();
try {
User user = userController.findUserByIdentifier(userIdentifier);
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
// TODO: User image
boolean hasImage = false;
return Response
.ok(new UserBasicInfo(userEntity.getId(), user.getFirstName(), user.getLastName(), user.getNickName(), user.getStudyProgrammeName(), hasImage, user.hasEvaluationFees(), user.getCurriculumIdentifier()))
.cacheControl(cacheControl)
.tag(tag)
.build();
} finally {
schoolDataBridgeSessionController.endSystemSession();
}
}
@GET
@Path("/staffMembers")
@RESTPermit (handling = Handling.INLINE)
public Response searchStaffMembers(
@QueryParam("searchString") String searchString,
@QueryParam("properties") String properties,
@QueryParam("workspaceEntityId") Long workspaceEntityId,
@QueryParam("firstResult") @DefaultValue("0") Integer firstResult,
@QueryParam("maxResults") @DefaultValue("10") Integer maxResults) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
List<fi.otavanopisto.muikku.rest.model.StaffMember> staffMembers = new ArrayList<>();
Set<Long> userGroupFilters = null;
Set<Long> workspaceFilters = workspaceEntityId == null ? null : Collections.singleton(workspaceEntityId);
List<SchoolDataIdentifier> userIdentifiers = null;
SearchProvider elasticSearchProvider = getProvider("elastic-search");
if (elasticSearchProvider != null) {
String[] fields = new String[] { "firstName", "lastName", "userEntityId" };
List<EnvironmentRoleArchetype> nonStudentArchetypes = new ArrayList<>(Arrays.asList(EnvironmentRoleArchetype.values()));
nonStudentArchetypes.remove(EnvironmentRoleArchetype.STUDENT);
SearchResult result = elasticSearchProvider.searchUsers(searchString,
fields,
nonStudentArchetypes,
userGroupFilters,
workspaceFilters,
userIdentifiers,
false,
false,
false,
firstResult,
maxResults);
List<Map<String, Object>> results = result.getResults();
if (results != null && !results.isEmpty()) {
String[] propertyArray = StringUtils.isEmpty(properties) ? new String[0] : properties.split(",");
for (Map<String, Object> o : results) {
String studentId = (String) o.get("id");
if (StringUtils.isBlank(studentId)) {
logger.severe("Could not process user found from search index because it had a null id");
continue;
}
String[] studentIdParts = studentId.split("/", 2);
SchoolDataIdentifier studentIdentifier = studentIdParts.length == 2 ? new SchoolDataIdentifier(studentIdParts[0], studentIdParts[1]) : null;
if (studentIdentifier == null) {
logger.severe(String.format("Could not process user found from search index with id %s", studentId));
continue;
}
if (studentIdentifier.getIdentifier().startsWith("STUDENT-")) {
// When the users are indexed, the archetype is resolved from EnvironmentUser,
// so there's 1 archetype per *UserEntity*, not 1 archetype per *User*.
// That means that if a userentity has both "student" users and "staffmember" users
// the elasticsearch query returns both. We need to filter them after the fact.
continue;
}
String email = userEmailEntityController.getUserDefaultEmailAddress(studentIdentifier, false);
Long userEntityId = new Long((Integer) o.get("userEntityId"));
UserEntity userEntity = userEntityController.findUserEntityById(userEntityId);
Map<String, String> propertyMap = new HashMap<String, String>();
if (userEntity != null) {
for (int i = 0; i < propertyArray.length; i++) {
UserEntityProperty userEntityProperty = userEntityController.getUserEntityPropertyByKey(userEntity, propertyArray[i]);
propertyMap.put(propertyArray[i], userEntityProperty == null ? null : userEntityProperty.getValue());
}
}
staffMembers.add(new fi.otavanopisto.muikku.rest.model.StaffMember(
studentIdentifier.toId(),
new Long((Integer) o.get("userEntityId")),
(String) o.get("firstName"),
(String) o.get("lastName"),
email,
propertyMap));
}
}
}
return Response.ok(staffMembers).build();
}
private fi.otavanopisto.muikku.rest.model.User createRestModel(UserEntity userEntity,
User user) {
// TODO: User Image
boolean hasImage = false;
String emailAddress = userEmailEntityController.getUserDefaultEmailAddress(userEntity, true);
Date startDate = user.getStudyStartDate() != null ? Date.from(user.getStudyStartDate().toInstant()) : null;
Date endDate = user.getStudyTimeEnd() != null ? Date.from(user.getStudyTimeEnd().toInstant()) : null;
return new fi.otavanopisto.muikku.rest.model.User(userEntity.getId(),
user.getFirstName(), user.getLastName(), user.getNickName(), hasImage,
user.getNationality(), user.getLanguage(),
user.getMunicipality(), user.getSchool(), emailAddress,
startDate, endDate);
}
private fi.otavanopisto.muikku.rest.model.StudentFlag createRestModel(FlagStudent flagStudent) {
SchoolDataIdentifier studentIdentifier = new SchoolDataIdentifier(flagStudent.getStudentIdentifier().getIdentifier(), flagStudent.getStudentIdentifier().getDataSource().getIdentifier());
return new fi.otavanopisto.muikku.rest.model.StudentFlag(flagStudent.getId(), flagStudent.getFlag().getId(), studentIdentifier.toId());
}
private List<fi.otavanopisto.muikku.rest.model.StudentFlag> createRestModel(FlagStudent[] flagStudents) {
List<fi.otavanopisto.muikku.rest.model.StudentFlag> result = new ArrayList<>();
for (FlagStudent flagStudent : flagStudents) {
result.add(createRestModel(flagStudent));
}
return result;
}
private fi.otavanopisto.muikku.rest.model.FlagShare createRestModel(FlagShare flagShare) {
SchoolDataIdentifier studentIdentifier = new SchoolDataIdentifier(flagShare.getUserIdentifier().getIdentifier(), flagShare.getUserIdentifier().getDataSource().getIdentifier());
return new fi.otavanopisto.muikku.rest.model.FlagShare(flagShare.getId(), flagShare.getFlag().getId(), studentIdentifier.toId());
}
private List<fi.otavanopisto.muikku.rest.model.FlagShare> createRestModel(FlagShare[] flagShares) {
List<fi.otavanopisto.muikku.rest.model.FlagShare> result = new ArrayList<>();
for (FlagShare flagShare : flagShares) {
result.add(createRestModel(flagShare));
}
return result;
}
private List<fi.otavanopisto.muikku.rest.model.TransferCredit> createRestModel(TransferCredit[] transferCredits) {
List<fi.otavanopisto.muikku.rest.model.TransferCredit> result = new ArrayList<>();
if (transferCredits != null) {
for (TransferCredit transferCredit : transferCredits) {
result.add(createRestModel(transferCredit));
}
}
return result;
}
private fi.otavanopisto.muikku.rest.model.TransferCredit createRestModel(TransferCredit transferCredit) {
return new fi.otavanopisto.muikku.rest.model.TransferCredit(
toId(transferCredit.getIdentifier()),
toId(transferCredit.getStudentIdentifier()),
transferCredit.getDate(),
toId(transferCredit.getGradeIdentifier()),
toId(transferCredit.getGradingScaleIdentifier()),
transferCredit.getVerbalAssessment(),
toId(transferCredit.getAssessorIdentifier()),
transferCredit.getCourseName(),
transferCredit.getCourseNumber(),
transferCredit.getLength(),
toId(transferCredit.getLengthUnitIdentifier()),
toId(transferCredit.getSchoolIdentifier()),
toId(transferCredit.getSubjectIdentifier()),
toId(transferCredit.getCurriculumIdentifier()));
}
private String toId(SchoolDataIdentifier identifier) {
if (identifier == null) {
return null;
}
return identifier.toId();
}
private SearchProvider getProvider(String name) {
Iterator<SearchProvider> i = searchProviders.iterator();
while (i.hasNext()) {
SearchProvider provider = i.next();
if (name.equals(provider.getName())) {
return provider;
}
}
return null;
}
private List<StudentPhoneNumber> createRestModel(UserPhoneNumber[] entities) {
List<StudentPhoneNumber> result = new ArrayList<>();
for (UserPhoneNumber entity : entities) {
result.add(new StudentPhoneNumber(toId(entity.getUserIdentifier()), entity.getType(), entity.getNumber(), entity.getDefaultNumber()));
}
return result;
}
private List<StudentEmail> createRestModel(UserEmail[] entities) {
List<StudentEmail> result = new ArrayList<>();
for (UserEmail entity : entities) {
result.add(new StudentEmail(toId(entity.getUserIdentifier()), entity.getType(), entity.getAddress(), entity.getDefaultAddress()));
}
return result;
}
private List<StudentAddress> createRestModel(UserAddress[] entities) {
List<StudentAddress> result = new ArrayList<>();
for (UserAddress entity : entities) {
result.add(new StudentAddress(
toId(entity.getIdentifier()),
toId(entity.getUserIdentifier()),
entity.getStreet(),
entity.getPostalCode(),
entity.getCity(),
entity.getRegion(),
entity.getCountry(),
entity.getType(),
entity.getDefaultAddress())
);
}
return result;
}
private fi.otavanopisto.muikku.rest.model.Flag createRestModel(Flag flag) {
SchoolDataIdentifier ownerIdentifier = new SchoolDataIdentifier(flag.getOwnerIdentifier().getIdentifier(), flag.getOwnerIdentifier().getDataSource().getIdentifier());
return new fi.otavanopisto.muikku.rest.model.Flag(flag.getId(), flag.getName(), flag.getColor(), flag.getDescription(), ownerIdentifier.toId());
}
private List<fi.otavanopisto.muikku.rest.model.Flag> createRestModel(Flag... flags) {
List<fi.otavanopisto.muikku.rest.model.Flag> result = new ArrayList<>(flags.length);
for (Flag flag : flags) {
result.add(createRestModel(flag));
}
return result;
}
}