package fi.otavanopisto.muikku.plugins.workspace.rest; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; 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.Level; import java.util.logging.Logger; 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.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.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.lang3.StringUtils; import fi.otavanopisto.muikku.controller.messaging.MessagingWidget; import fi.otavanopisto.muikku.model.users.EnvironmentRoleArchetype; import fi.otavanopisto.muikku.model.users.Flag; import fi.otavanopisto.muikku.model.users.UserEntity; import fi.otavanopisto.muikku.model.users.UserSchoolDataIdentifier; import fi.otavanopisto.muikku.model.workspace.WorkspaceEntity; import fi.otavanopisto.muikku.model.workspace.WorkspaceMaterialProducer; import fi.otavanopisto.muikku.model.workspace.WorkspaceUserEntity; import fi.otavanopisto.muikku.plugin.PluginRESTService; import fi.otavanopisto.muikku.plugins.assessmentrequest.AssessmentRequestController; import fi.otavanopisto.muikku.plugins.material.MaterialController; import fi.otavanopisto.muikku.plugins.material.model.HtmlMaterial; import fi.otavanopisto.muikku.plugins.material.model.Material; import fi.otavanopisto.muikku.plugins.material.model.MaterialViewRestrict; import fi.otavanopisto.muikku.plugins.search.WorkspaceIndexer; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceJournalController; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialContainsAnswersExeption; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialController; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialDeleteError; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialFieldAnswerController; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialFieldController; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceMaterialReplyController; import fi.otavanopisto.muikku.plugins.workspace.WorkspaceVisitController; import fi.otavanopisto.muikku.plugins.workspace.fieldio.WorkspaceFieldIOException; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceFolder; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceJournalEntry; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterial; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialAssignmentType; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialAudioFieldAnswerClip; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialField; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialFileFieldAnswerFile; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReplyState; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceNode; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceNodeType; import fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceRootFolder; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceCompositeReply; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceDetails; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceFeeInfo; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceJournalEntryRESTModel; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialCompositeReply; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialFieldAnswer; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialReply; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceStaffMember; import fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceStudent; import fi.otavanopisto.muikku.rest.RESTPermitUnimplemented; import fi.otavanopisto.muikku.schooldata.CourseMetaController; 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.WorkspaceController; import fi.otavanopisto.muikku.schooldata.WorkspaceEntityController; import fi.otavanopisto.muikku.schooldata.entity.EducationType; 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.muikku.search.SearchProvider; import fi.otavanopisto.muikku.search.SearchProvider.Sort; import fi.otavanopisto.muikku.search.SearchResult; import fi.otavanopisto.muikku.security.MuikkuPermissions; import fi.otavanopisto.muikku.session.SessionController; import fi.otavanopisto.muikku.users.FlagController; import fi.otavanopisto.muikku.users.UserController; import fi.otavanopisto.muikku.users.UserEntityController; import fi.otavanopisto.muikku.users.WorkspaceUserEntityController; import fi.otavanopisto.security.rest.RESTPermit; import fi.otavanopisto.security.rest.RESTPermit.Handling; @RequestScoped @Stateful @Produces("application/json") @Path ("/workspace") @RestCatchSchoolDataExceptions public class WorkspaceRESTService extends PluginRESTService { private static final long serialVersionUID = -5286350366083446537L; @Inject private Logger logger; @Inject private WorkspaceController workspaceController; @Inject private CourseMetaController courseMetaController; @Inject private WorkspaceEntityController workspaceEntityController; @Inject private WorkspaceUserEntityController workspaceUserEntityController; @Inject private AssessmentRequestController assessmentRequestController; @Inject private SessionController sessionController; @Inject private UserController userController; @Inject private UserEntityController userEntityController; @Inject private WorkspaceMaterialController workspaceMaterialController; @Inject private WorkspaceMaterialReplyController workspaceMaterialReplyController; @Inject private WorkspaceMaterialFieldAnswerController workspaceMaterialFieldAnswerController; @Inject private MaterialController materialController; @Inject private WorkspaceMaterialFieldController workspaceMaterialFieldController; @Inject private SchoolDataBridgeSessionController schoolDataBridgeSessionController; @Inject @Any private Instance<SearchProvider> searchProviders; @Inject @Any private Instance<MessagingWidget> messagingWidgets; @Inject private WorkspaceVisitController workspaceVisitController; @Inject private GradingController gradingController; @Inject private WorkspaceIndexer workspaceIndexer; @Inject private WorkspaceJournalController workspaceJournalController; @Inject private CopiedWorkspaceEntityIdFinder copiedWorkspaceEntityIdFinder; @Inject private FlagController flagController; @GET @Path("/workspaceTypes") @RESTPermit (requireLoggedIn = false, handling = Handling.UNSECURED) public Response listWorkspaceTypes() { List<WorkspaceType> types = workspaceController.listWorkspaceTypes(); return Response.ok(createRestModel(types.toArray(new WorkspaceType[0]))).build(); } @GET @Path("/educationTypes") @RESTPermit (requireLoggedIn = false, handling = Handling.UNSECURED) public Response listEducationTypes() { schoolDataBridgeSessionController.startSystemSession(); try { List<EducationType> types = courseMetaController.listEducationTypes(); return Response.ok(createRestModel(types.toArray(new EducationType[0]))).build(); } finally { schoolDataBridgeSessionController.endSystemSession(); } } @POST @Path("/workspaces/") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response createWorkspace(@QueryParam ("sourceWorkspaceIdentifier") String sourceWorkspaceId, @QueryParam ("sourceWorkspaceEntityId") Long sourceWorkspaceEntityId, fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace payload) { SchoolDataIdentifier workspaceIdentifier = null; if (sourceWorkspaceId != null) { workspaceIdentifier = SchoolDataIdentifier.fromId(sourceWorkspaceId); if (workspaceIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid source workspace identifier %s", sourceWorkspaceId)).build(); } } WorkspaceEntity sourceWorkspaceEntity = null; if (sourceWorkspaceEntityId != null) { sourceWorkspaceEntity = workspaceEntityController.findWorkspaceEntityById(sourceWorkspaceEntityId); if (sourceWorkspaceEntity == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid source workspace entity id %d", sourceWorkspaceEntityId)).build(); } workspaceIdentifier = new SchoolDataIdentifier(sourceWorkspaceEntity.getIdentifier(), sourceWorkspaceEntity.getDataSource().getIdentifier()); } if (workspaceIdentifier == null) { return Response.status(Status.NOT_IMPLEMENTED).entity("Creating new workspaces without sourceWorkspace is not not implemented yet").build(); } if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.COPY_WORKSPACE)) { return Response.status(Status.FORBIDDEN).build(); } if (StringUtils.isBlank(payload.getName())) { return Response.status(Status.BAD_REQUEST).entity("Name is required").build(); } Workspace workspace = workspaceController.copyWorkspace(workspaceIdentifier, payload.getName(), payload.getNameExtension(), payload.getDescription()); if (workspace == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity(String.format("Failed to create copy of workspace %s", sourceWorkspaceId)).build(); } WorkspaceEntity workspaceEntity = findCopiedWorkspaceEntity(workspace); if (workspaceEntity == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity(String.format("Failed to create local copy of workspace %s", sourceWorkspaceId)).build(); } // #2599: Also copy workspace default license and producers if (sourceWorkspaceEntity != null) { workspaceEntityController.updateDefaultMaterialLicense(workspaceEntity, sourceWorkspaceEntity.getDefaultMaterialLicense()); List<WorkspaceMaterialProducer> workspaceMaterialProducers = workspaceController.listWorkspaceMaterialProducers(sourceWorkspaceEntity); for (WorkspaceMaterialProducer workspaceMaterialProducer : workspaceMaterialProducers) { workspaceController.createWorkspaceMaterialProducer(workspaceEntity, workspaceMaterialProducer.getName()); } } return Response .ok(createRestModel(workspaceEntity, workspace.getName(), workspace.getNameExtension(), workspace.getDescription(), convertWorkspaceCurriculumIds(workspace))) .build(); } private Set<String> convertWorkspaceCurriculumIds(Workspace workspace) { Set<String> curriculumIdentifiers = new HashSet<String>(); if (workspace.getCurriculumIdentifiers() != null) workspace.getCurriculumIdentifiers().forEach((SchoolDataIdentifier id) -> curriculumIdentifiers.add(id.toId())); return curriculumIdentifiers; } private WorkspaceEntity findCopiedWorkspaceEntity(Workspace workspace) { WorkspaceEntity workspaceEntity = null; Long workspaceEntityId = null; long timeoutTime = System.currentTimeMillis() + 60000; while (workspaceEntityId == null) { workspaceEntityId = copiedWorkspaceEntityIdFinder.findCopiedWorkspaceEntityId(workspace); if (System.currentTimeMillis() > timeoutTime) { logger.severe("Timeouted when waiting for copied workspace entity"); return null; } if (workspaceEntityId == null) { try { Thread.sleep(10); } catch (InterruptedException e) { } } else { workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); } } return workspaceEntity; } @GET @Path("/workspaces/") @RESTPermit (handling = Handling.INLINE) public Response listWorkspaces( @QueryParam("userId") Long userEntityId, @QueryParam("userIdentifier") String userId, @QueryParam("includeArchivedWorkspaceUsers") @DefaultValue ("false") Boolean includeArchivedWorkspaceUsers, @QueryParam("search") String searchString, @QueryParam("subjects") List<String> subjects, @QueryParam("educationTypes") List<String> educationTypeIds, @QueryParam("curriculums") List<String> curriculumIds, @QueryParam("minVisits") Long minVisits, @QueryParam("includeUnpublished") @DefaultValue ("false") Boolean includeUnpublished, @QueryParam("orderBy") List<String> orderBy, @QueryParam("firstResult") @DefaultValue ("0") Integer firstResult, @QueryParam("maxResults") @DefaultValue ("50") Integer maxResults, @Context Request request) { List<fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace> workspaces = new ArrayList<>(); boolean doMinVisitFilter = minVisits != null; UserEntity userEntity = userEntityId != null ? userEntityController.findUserEntityById(userEntityId) : null; List<WorkspaceEntity> workspaceEntities = null; String schoolDataSourceFilter = null; List<String> workspaceIdentifierFilters = null; SchoolDataIdentifier userIdentifier = SchoolDataIdentifier.fromId(userId); if (userIdentifier != null) { if (doMinVisitFilter && userEntity == null) { userEntity = userEntityController.findUserEntityByUserIdentifier(userIdentifier); } } if (includeArchivedWorkspaceUsers && (userIdentifier == null)) { return Response.status(Status.BAD_REQUEST).entity("includeArchivedWorkspaceUsers works only with userIdentifier parameter").build(); } if (includeArchivedWorkspaceUsers && doMinVisitFilter) { return Response.status(Status.BAD_REQUEST).entity("includeArchivedWorkspaceUsers and doMinVisitFilter are ").build(); } if (doMinVisitFilter) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("You need to be logged in to filter by visit count").build(); } UserEntity loggedUserEntity = sessionController.getLoggedUserEntity(); workspaceEntities = workspaceVisitController.listEnrolledWorkspaceEntitiesByMinVisitsOrderByLastVisit(loggedUserEntity, minVisits); } else { if (userIdentifier != null) { if (includeArchivedWorkspaceUsers) { workspaceEntities = workspaceUserEntityController.listWorkspaceEntitiesByUserIdentifierIncludeArchived(userIdentifier); } else { workspaceEntities = workspaceUserEntityController.listWorkspaceEntitiesByUserIdentifier(userIdentifier); } } else if (userEntity != null) { workspaceEntities = workspaceUserEntityController.listWorkspaceEntitiesByUserEntity(userEntity); } else { if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_ALL_WORKSPACES)) { return Response.status(Status.FORBIDDEN).build(); } workspaceEntities = Boolean.TRUE.equals(includeUnpublished) ? workspaceController.listWorkspaceEntities() : workspaceController.listPublishedWorkspaceEntities(); } } Iterator<SearchProvider> searchProviderIterator = searchProviders.iterator(); if (searchProviderIterator.hasNext()) { SearchProvider searchProvider = searchProviderIterator.next(); SearchResult searchResult = null; if (workspaceEntities != null) { workspaceIdentifierFilters = new ArrayList<>(); for (WorkspaceEntity workspaceEntity : workspaceEntities) { if (schoolDataSourceFilter == null) { schoolDataSourceFilter = workspaceEntity.getDataSource().getIdentifier(); } workspaceIdentifierFilters.add(workspaceEntity.getIdentifier()); } } List<Sort> sorts = null; if (orderBy != null && orderBy.contains("alphabet")) { sorts = new ArrayList<>(); sorts.add(new Sort("name.untouched", Sort.Order.ASC)); } List<SchoolDataIdentifier> educationTypes = null; if (educationTypeIds != null) { educationTypes = new ArrayList<>(educationTypeIds.size()); for (String educationTypeId : educationTypeIds) { SchoolDataIdentifier educationTypeIdentifier = SchoolDataIdentifier.fromId(educationTypeId); if (educationTypeIdentifier != null) { educationTypes.add(educationTypeIdentifier); } else { return Response.status(Status.BAD_REQUEST).entity(String.format("Malformed education type identifier", educationTypeId)).build(); } } } List<SchoolDataIdentifier> curriculums = null; if (curriculumIds != null) { curriculums = new ArrayList<>(curriculumIds.size()); for (String curriculumId : curriculumIds) { SchoolDataIdentifier curriculumIdentifier = SchoolDataIdentifier.fromId(curriculumId); if (curriculumIdentifier != null) { curriculums.add(curriculumIdentifier); } else { return Response.status(Status.BAD_REQUEST).entity(String.format("Malformed curriculum identifier", curriculumId)).build(); } } } searchResult = searchProvider.searchWorkspaces(schoolDataSourceFilter, subjects, workspaceIdentifierFilters, educationTypes, curriculums, searchString, null, null, includeUnpublished, firstResult, maxResults, sorts); List<Map<String, Object>> results = searchResult.getResults(); for (Map<String, Object> result : results) { String searchId = (String) result.get("id"); if (StringUtils.isNotBlank(searchId)) { String[] id = searchId.split("/", 2); if (id.length == 2) { String dataSource = id[1]; String identifier = id[0]; WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceByDataSourceAndIdentifier(dataSource, identifier); if (workspaceEntity != null) { String name = (String) result.get("name"); String description = (String) result.get("description"); String nameExtension = (String) result.get("nameExtension"); Object curriculumIdentifiersObject = result.get("curriculumIdentifiers"); Set<String> curriculumIdentifiers = new HashSet<String>(); if (curriculumIdentifiersObject instanceof Collection) { Collection<?> curriculumIdentifierCollection = (Collection<?>) curriculumIdentifiersObject; for (Object o : curriculumIdentifierCollection) { if (o instanceof String) curriculumIdentifiers.add((String) o); else logger.warning("curriculumIdentifier not of type String"); } } if (StringUtils.isNotBlank(name)) { workspaces.add(createRestModel(workspaceEntity, name, nameExtension, description, curriculumIdentifiers)); } } } } } } else { return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } if (workspaces.isEmpty()) { return Response.noContent().build(); } if (orderBy.contains("lastVisit")) { Collections.sort(workspaces, new Comparator<fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace>() { @Override public int compare(fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace workspace1, fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace workspace2) { if (workspace1.getLastVisit() == null || workspace2.getLastVisit() == null) { return 0; } if (workspace1.getLastVisit().before(workspace2.getLastVisit())) { return 1; } if (workspace1.getLastVisit().after(workspace2.getLastVisit())) { return -1; } return 0; } }); } return Response.ok(workspaces).build(); } @GET @Path("/workspaces/{ID}") @RESTPermitUnimplemented public Response getWorkspace(@PathParam("ID") Long workspaceEntityId) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } Workspace workspace = null; schoolDataBridgeSessionController.startSystemSession(); try { workspace = workspaceController.findWorkspace(workspaceEntity); } finally { schoolDataBridgeSessionController.endSystemSession(); } if (workspace == null) { return Response.status(Status.NOT_FOUND).build(); } return Response.ok(createRestModel(workspaceEntity, workspace.getName(), workspace.getNameExtension(), workspace.getDescription(), convertWorkspaceCurriculumIds(workspace))).build(); } @GET @Path("/workspaces/{ID}/details") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response getWorkspaceDetails(@PathParam("ID") Long workspaceEntityId) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.VIEW_WORKSPACE_DETAILS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } Workspace workspace = workspaceController.findWorkspace(workspaceEntity); if (workspace == null) { return Response.status(Status.NOT_FOUND).build(); } String typeId = workspace.getWorkspaceTypeId() != null ? workspace.getWorkspaceTypeId().toId() : null; return Response.ok(new WorkspaceDetails(typeId, workspace.getBeginDate(), workspace.getEndDate(), workspace.getViewLink())).build(); } @POST @Path("/workspaces/{WORKSPACEENTITYID}/materialProducers") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response createWorkspaceMaterialProducer(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, WorkspaceMaterialProducer payload) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIAL_PRODUCERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceMaterialProducer materialProducer = workspaceController.createWorkspaceMaterialProducer(workspaceEntity, payload.getName()); return Response .ok(createRestModel(materialProducer)) .build(); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/materialProducers") @RESTPermit (handling = Handling.INLINE) public Response listWorkspaceMaterialProducers(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } if (workspaceEntity.getArchived()) { return Response.status(Status.NOT_FOUND).build(); } if (!workspaceEntity.getPublished()) { if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIAL_PRODUCERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIAL_PRODUCERS, workspaceEntity)) { switch (workspaceEntity.getAccess()) { case ANYONE: break; case LOGGED_IN: if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } break; case MEMBERS_ONLY: if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityController.findWorkspaceUserByWorkspaceEntityAndUserIdentifier(workspaceEntity, sessionController.getLoggedUser()); if (workspaceUserEntity == null) { if (!sessionController.hasWorkspacePermission(MuikkuPermissions.ACCESS_MEMBERS_ONLY_WORKSPACE, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } } break; } } return Response .ok(createRestModel(workspaceController.listWorkspaceMaterialProducers(workspaceEntity).toArray(new WorkspaceMaterialProducer[0]))) .build(); } @DELETE @Path("/workspaces/{WORKSPACEENTITYID}/materialProducers/{ID}") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response deleteWorkspaceMaterialProducer(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("ID") Long workspaceMaterialProducerId) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIAL_PRODUCERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceMaterialProducer materialProducer = workspaceController.findWorkspaceMaterialProducer(workspaceMaterialProducerId); workspaceController.deleteWorkspaceMaterialProducer(materialProducer); return Response .noContent() .build(); } @PUT @Path("/workspaces/{ID}/details") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response updateWorkspaceDetails(@PathParam("ID") Long workspaceEntityId, WorkspaceDetails payload) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } Workspace workspace = workspaceController.findWorkspace(workspaceEntity); if (workspace == null) { return Response.status(Status.NOT_FOUND).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_DETAILS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } if ((payload.getExternalViewUrl() != null) && (!StringUtils.equals(workspace.getViewLink(), payload.getExternalViewUrl()))) { return Response.status(Status.BAD_REQUEST).entity("externalViewUrl is read-only property").build(); } SchoolDataIdentifier typeIdentifier = null; if (payload.getTypeId() != null) { typeIdentifier = SchoolDataIdentifier.fromId(payload.getTypeId()); if (typeIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invlid typeId %s", payload.getTypeId())).build(); } } if (!isEqualDateTime(workspace.getBeginDate(), payload.getBeginDate()) || !isEqualDateTime(workspace.getEndDate(), payload.getEndDate()) || !Objects.equals(typeIdentifier, workspace.getWorkspaceTypeId())) { workspace.setBeginDate(payload.getBeginDate()); workspace.setEndDate(payload.getEndDate()); workspace.setWorkspaceTypeId(typeIdentifier); workspaceController.updateWorkspace(workspace); } String typeId = workspace.getWorkspaceTypeId() != null ? workspace.getWorkspaceTypeId().toId() : null; return Response.ok(new WorkspaceDetails(typeId, workspace.getBeginDate(), workspace.getEndDate(), workspace.getViewLink())).build(); } private boolean isEqualDateTime(OffsetDateTime dateTime1, OffsetDateTime dateTime2) { if (dateTime1 == dateTime2) { return true; } if (dateTime1 != null) { return dateTime1.equals(dateTime2); } else { return dateTime2.equals(dateTime1); } } @PUT @Path("/workspaces/{WORKSPACEENTITYID}") @RESTPermitUnimplemented public Response updateWorkspace(@PathParam ("WORKSPACEENTITYID") Long workspaceEntityId, fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace payload) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity(String.format("WorkspaceEntity #%d not found", workspaceEntityId)).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.PUBLISH_WORKSPACE, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } if ((payload.getArchived() != null) && payload.getArchived()) { return Response.status(Status.NOT_IMPLEMENTED).entity("Archiving workspaces is currently unimplemented").build(); } Workspace workspace = null; try { workspace = workspaceController.findWorkspace(workspaceEntity); if (workspace == null) { return Response.status(Status.NOT_FOUND).entity(String.format("Could not find a workspace for WorkspaceEntity #%d", workspaceEntityId)).build(); } } catch (Exception e) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity(String.format("Failed to retrieve workspace from school data source (%s)", e.getMessage())).build(); } if ((payload.getDescription() != null) || (payload.getName() != null)) { try { if ((!StringUtils.equals(payload.getName(), workspace.getName())) || (!StringUtils.equals(payload.getDescription(), workspace.getDescription())) || (!StringUtils.equals(payload.getNameExtension(), workspace.getNameExtension()))) { workspace.setName(payload.getName()); workspace.setNameExtension(payload.getNameExtension()); workspace.setDescription(payload.getDescription()); workspace = workspaceController.updateWorkspace(workspace); } } catch (Exception e) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity(String.format("Failed to update workspace data into school data source (%s)", e.getMessage())).build(); } } if (payload.getNumVisits() != null) { if (workspaceVisitController.getNumVisits(workspaceEntity) != payload.getNumVisits().longValue()) { return Response.status(Status.NOT_IMPLEMENTED).entity("Updating number of visit via this endpoint is currently unimplemented").build(); } } if (payload.getLastVisit() != null) { if (workspaceVisitController.getLastVisit(workspaceEntity).equals(payload.getLastVisit())) { return Response.status(Status.NOT_IMPLEMENTED).entity("Updating last visit via this endpoint is currently unimplemented").build(); } } if (payload.getPublished() != null && !workspaceEntity.getPublished().equals(payload.getPublished())) { workspaceEntityController.updatePublished(workspaceEntity, payload.getPublished()); } workspaceEntityController.updateAccess(workspaceEntity, payload.getAccess()); workspaceEntityController.updateDefaultMaterialLicense(workspaceEntity, payload.getMaterialDefaultLicense()); // Reindex the workspace so that Elasticsearch can react to publish/unpublish workspaceIndexer.indexWorkspace(workspaceEntity); return Response.ok(createRestModel(workspaceEntity, workspace.getName(), workspace.getNameExtension(), workspace.getDescription(), convertWorkspaceCurriculumIds(workspace))).build(); } @GET @Path("/workspaces/{ID}/students") @RESTPermit (handling = Handling.INLINE) public Response listWorkspaceStudents(@PathParam("ID") Long workspaceEntityId, @QueryParam("archived") Boolean archived, @QueryParam("requestedAssessment") Boolean requestedAssessment, @QueryParam("assessed") Boolean assessed, @QueryParam("studentIdentifier") String studentId, @QueryParam("search") String searchString, @QueryParam("flags") Long[] flagIds, @QueryParam("maxResults") Integer maxResults, @QueryParam("orderBy") String orderBy) { List<SchoolDataIdentifier> studentIdentifiers = null; if (StringUtils.isNotBlank(studentId)) { SchoolDataIdentifier studentIdentifier = SchoolDataIdentifier.fromId(studentId); if (studentIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Malformed student identifier %s", studentId)).build(); } studentIdentifiers = Collections.singletonList(studentIdentifier); } // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } // Access check if (!sessionController.hasWorkspacePermission(MuikkuPermissions.LIST_WORKSPACE_MEMBERS, workspaceEntity)) { if (studentIdentifiers == null || studentIdentifiers.size() != 1 || !studentIdentifiers.get(0).equals(sessionController.getLoggedUser())) { return Response.status(Status.FORBIDDEN).build(); } } List<fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser> workspaceUsers = null; if (searchString != null) { studentIdentifiers = new ArrayList<>(); Iterator<SearchProvider> searchProviderIterator = searchProviders.iterator(); if (!searchProviderIterator.hasNext()) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("No search provider found").build(); } SearchProvider elasticSearchProvider = searchProviderIterator.next(); if (elasticSearchProvider != null) { String[] fields = new String[] { "firstName", "lastName", "nickName" }; SearchResult result = elasticSearchProvider.searchUsers( searchString, fields, Arrays.asList(EnvironmentRoleArchetype.STUDENT), (Collection<Long>)null, Collections.singletonList(workspaceEntityId), (Collection<SchoolDataIdentifier>) null, Boolean.FALSE, Boolean.FALSE, false, 0, maxResults != null ? maxResults : Integer.MAX_VALUE); List<Map<String, Object>> results = result.getResults(); if (results != null && !results.isEmpty()) { for (Map<String, Object> o : results) { String foundStudentId = (String) o.get("id"); if (StringUtils.isBlank(foundStudentId)) { logger.severe("Could not process user found from search index because it had a null id"); continue; } String[] studentIdParts = foundStudentId.split("/", 2); SchoolDataIdentifier foundStudentIdentifier = studentIdParts.length == 2 ? new SchoolDataIdentifier(studentIdParts[0], studentIdParts[1]) : null; if (foundStudentIdentifier == null) { logger.severe(String.format("Could not process user found from search index with id %s", studentId)); continue; } studentIdentifiers.add(foundStudentIdentifier); } } } } 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); } } if (flags != null) { List<SchoolDataIdentifier> flaggedStudents = flagController.getFlaggedStudents(flags); if (studentIdentifiers != null) { studentIdentifiers.retainAll(flaggedStudents); } else { studentIdentifiers = flaggedStudents; } } List<WorkspaceStudent> result = new ArrayList<>(); if (studentIdentifiers != null) { workspaceUsers = new ArrayList<>(); for (SchoolDataIdentifier studentIdentifier : studentIdentifiers) { WorkspaceUserEntity wue = workspaceUserEntityController.findWorkspaceUserByWorkspaceEntityAndUserIdentifier(workspaceEntity, studentIdentifier); if (wue == null) { continue; } if (!archived && wue.getArchived()) { continue; } WorkspaceUser workspaceUser = workspaceController.findWorkspaceUser(wue); if (workspaceUser == null) { continue; } workspaceUsers.add(workspaceUser); } } else { // Students via WorkspaceSchoolDataBridge workspaceUsers = workspaceController.listWorkspaceStudents(workspaceEntity); } if (workspaceUsers == null || workspaceUsers.isEmpty()) { return Response.noContent().build(); } Map<String, WorkspaceUserEntity> workspaceUserEntityMap = new HashMap<>(); List<WorkspaceUserEntity> workspaceUserEntities = workspaceUserEntityController.listWorkspaceUserEntities(workspaceEntity); for (WorkspaceUserEntity workspaceUserEntity : workspaceUserEntities) { workspaceUserEntityMap.put(new SchoolDataIdentifier(workspaceUserEntity.getIdentifier(), workspaceUserEntity.getUserSchoolDataIdentifier().getDataSource().getIdentifier()).toId(), workspaceUserEntity); } if (maxResults != null && workspaceUsers.size() > maxResults) { workspaceUsers.subList(maxResults, workspaceUsers.size() - 1).clear(); } for (fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser workspaceUser : workspaceUsers) { SchoolDataIdentifier workspaceUserIdentifier = workspaceUser.getIdentifier(); WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityMap.get(workspaceUserIdentifier.toId()); boolean userArchived = workspaceUserEntity == null; if ((archived == null) || (archived.equals(userArchived))) { if (requestedAssessment != null) { boolean hasAssessmentRequest = workspaceUserEntity != null && !assessmentRequestController.listByWorkspaceUser(workspaceUserEntity).isEmpty(); if (requestedAssessment != hasAssessmentRequest) { continue; } } if (assessed != null) { boolean isAssessed = !gradingController.listWorkspaceAssessments(workspaceUser.getWorkspaceIdentifier(), workspaceUser.getUserIdentifier()).isEmpty(); if (assessed != isAssessed) { continue; } } SchoolDataIdentifier userIdentifier = workspaceUser.getUserIdentifier(); User user = userController.findUserByIdentifier(userIdentifier); if (user != null) { UserEntity userEntity = null; if (workspaceUserEntity != null) { userEntity = workspaceUserEntity.getUserSchoolDataIdentifier().getUserEntity(); } else { userEntity = userEntityController.findUserEntityByDataSourceAndIdentifier(user.getSchoolDataSource(), user.getIdentifier()); } result.add(createRestModel(userEntity, user, workspaceUser, userArchived)); } else { logger.log(Level.SEVERE, String.format("Could not find user for identifier %s", userIdentifier)); } } } // Sorting if (StringUtils.equals(orderBy, "name")) { Collections.sort(result, new Comparator<WorkspaceStudent>() { @Override public int compare(WorkspaceStudent o1, WorkspaceStudent o2) { String s1 = String.format("%s, %s", StringUtils.defaultString(o1.getLastName(), ""), StringUtils.defaultString(o1.getFirstName(), "")); String s2 = String.format("%s, %s", StringUtils.defaultString(o2.getLastName(), ""), StringUtils.defaultString(o2.getFirstName(), "")); return s1.compareTo(s2); } }); } // Response return Response.ok(result).build(); } private WorkspaceStudent createRestModel(UserEntity userEntity, User user, WorkspaceUser workspaceUser, boolean userArchived) { SchoolDataIdentifier userIdentifier = new SchoolDataIdentifier(user.getIdentifier(), user.getSchoolDataSource()); String firstName = user.getFirstName(); String lastName = user.getLastName(); String studyProgrammeName = user.getStudyProgrammeName(); OffsetDateTime enrolmentTime = workspaceUser.getEnrolmentTime(); return new WorkspaceStudent(workspaceUser.getIdentifier().toId(), userEntity != null ? userEntity.getId() : null, userIdentifier.toId(), firstName, lastName, studyProgrammeName, enrolmentTime != null ? Date.from(enrolmentTime.toInstant()) : null, userArchived); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/evaluatedAssignmentInfo") @RESTPermit(handling = Handling.INLINE, requireLoggedIn = true) public Response getEvaluatedAssignmentInfo(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId) { Map<String, Long> result = new HashMap<String, Long>(); // Workspace and user WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } UserEntity userEntity = sessionController.getLoggedUserEntity(); // Total number of evaluated assignments List<WorkspaceMaterial> evaluatedAssignments = workspaceMaterialController.listVisibleWorkspaceMaterialsByAssignmentType( workspaceEntity, WorkspaceMaterialAssignmentType.EVALUATED); result.put("assignmentsTotal", new Long(evaluatedAssignments.size())); // Done number of evaluated assignments List<WorkspaceMaterialReplyState> replyStates = new ArrayList<WorkspaceMaterialReplyState>(); replyStates.add(WorkspaceMaterialReplyState.FAILED); replyStates.add(WorkspaceMaterialReplyState.PASSED); replyStates.add(WorkspaceMaterialReplyState.SUBMITTED); Long assignmentsDone = workspaceMaterialReplyController.getReplyCountByUserEntityAndReplyStatesAndWorkspaceMaterials(userEntity.getId(), replyStates, evaluatedAssignments); result.put("assignmentsDone", assignmentsDone); return Response.ok(result).build(); } @GET @Path("/workspaces/{ID}/feeInfo") @RESTPermit(value = MuikkuPermissions.VIEW_WORKSPACE_FEE, requireLoggedIn = true) public Response getFeeInfo(@PathParam("ID") Long workspaceEntityId) { SchoolDataIdentifier userIdentifier = sessionController.getLoggedUser(); if (userIdentifier == null) { return Response.status(Status.UNAUTHORIZED).build(); } User user = userController.findUserByIdentifier(userIdentifier); if (user == null) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } Workspace workspace = workspaceController.findWorkspace(workspaceEntity); if (workspace == null) { return Response.status(Status.NOT_FOUND).build(); } // #3069: If the user has evaluation fees and a school set, all workspaces have an // evaluation fee. Otherwise it depends on the applicability of the workspace itself. boolean evaluationFees = user.hasEvaluationFees() && (StringUtils.isNotEmpty(user.getSchool()) || workspace.isEvaluationFeeApplicable()); return Response.ok(new WorkspaceFeeInfo(evaluationFees)).build(); } @GET @Path("/workspaces/{ID}/staffMembers") @RESTPermitUnimplemented public Response listWorkspaceStaffMembers(@PathParam("ID") Long workspaceEntityId, @QueryParam("orderBy") String orderBy) { // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } // Access check if (!sessionController.hasWorkspacePermission(MuikkuPermissions.LIST_WORKSPACE_MEMBERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } // Staff via WorkspaceSchoolDataBridge List<fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser> schoolDataUsers = workspaceController.listWorkspaceStaffMembers(workspaceEntity); List<WorkspaceStaffMember> workspaceStaffMembers = new ArrayList<>(); for (fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser workspaceUser : schoolDataUsers) { SchoolDataIdentifier userIdentifier = workspaceUser.getUserIdentifier(); User user = userController.findUserByIdentifier(userIdentifier); if (user != null) { UserEntity userEntity = userEntityController.findUserEntityByUser(user); workspaceStaffMembers.add(new WorkspaceStaffMember(workspaceUser.getIdentifier().toId(), workspaceUser.getUserIdentifier().toId(), userEntity != null ? userEntity.getId() : null, user.getFirstName(), user.getLastName() )); } else { logger.log(Level.SEVERE, String.format("Could not find user %s", userIdentifier)); } } // Sorting if (StringUtils.equals(orderBy, "name")) { Collections.sort(workspaceStaffMembers, new Comparator<WorkspaceStaffMember>() { @Override public int compare(WorkspaceStaffMember o1, WorkspaceStaffMember o2) { String s1 = String.format("%s, %s", StringUtils.defaultString(o1.getLastName(), ""), StringUtils.defaultString(o1.getFirstName(), "")); String s2 = String.format("%s, %s", StringUtils.defaultString(o2.getLastName(), ""), StringUtils.defaultString(o2.getFirstName(), "")); return s1.compareTo(s2); } }); } // Response return Response.ok(workspaceStaffMembers).build(); } @POST @Path("/workspaces/{ID}/materials/") @RESTPermitUnimplemented public Response createWorkspaceMaterial(@PathParam("ID") Long workspaceEntityId, @QueryParam("sourceNodeId") Long sourceNodeId, @QueryParam("targetNodeId") Long targetNodeId, @QueryParam("sourceWorkspaceEntityId") Long sourceWorkspaceEntityId, @QueryParam("targetWorkspaceEntityId") Long targetWorkspaceEntityId, @QueryParam("copyOnlyChildren") Boolean copyOnlyChildren, @QueryParam("cloneMaterials") @DefaultValue ("false") Boolean cloneMaterials, @QueryParam("updateLinkedMaterials") @DefaultValue ("false") Boolean updateLinkedMaterials, fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial entity) { WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } if ((sourceNodeId != null) || (sourceWorkspaceEntityId != null)) { // When source is specified the operation will be copy instead of create if (sourceNodeId == null) { WorkspaceEntity sourceWorkspaceEntity = workspaceController.findWorkspaceEntityById(sourceWorkspaceEntityId); if (sourceWorkspaceEntity == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid sourceWorkspaceEntity %d", sourceWorkspaceEntityId)).build(); } WorkspaceRootFolder sourceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceEntity(sourceWorkspaceEntity); if (sourceRootFolder == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid sourceWorkspaceEntity %d", sourceWorkspaceEntityId)).build(); } sourceNodeId = sourceRootFolder.getId(); } if (targetNodeId == null) { if (targetWorkspaceEntityId != null) { WorkspaceEntity targetWorkspaceEntity = workspaceController.findWorkspaceEntityById(targetWorkspaceEntityId); if (targetWorkspaceEntity == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid targetWorkspaceEntity %d", sourceWorkspaceEntityId)).build(); } WorkspaceRootFolder targetRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceEntity(targetWorkspaceEntity); if (targetRootFolder == null) { return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid targetWorkspaceEntity %d", sourceWorkspaceEntityId)).build(); } targetNodeId = targetRootFolder.getId(); } } if (targetNodeId == null) { return Response.status(Status.BAD_REQUEST).entity("targetNodeId is required when sourceNodeId is specified").build(); } // Access if (!sessionController.hasEnvironmentPermission(MuikkuPermissions.COPY_WORKSPACE)) { return Response.status(Status.FORBIDDEN).build(); } // Source WorkspaceNode sourceNode = workspaceMaterialController.findWorkspaceNodeById(sourceNodeId); if (sourceNode == null) { return Response.status(Status.BAD_REQUEST).entity("null source").build(); } // Target WorkspaceNode targetNode = workspaceMaterialController.findWorkspaceNodeById(targetNodeId); if (targetNode == null) { return Response.status(Status.BAD_REQUEST).entity("null target").build(); } WorkspaceRootFolder targetRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(targetNode); if (!targetRootFolder.getWorkspaceEntityId().equals(workspaceEntity.getId())) { return Response.status(Status.BAD_REQUEST).entity(String.format("targetNode does not belong to workspace entity %d", workspaceEntity.getId())).build(); } // Circular reference check WorkspaceNode node = targetNode; while (node != null) { if (node.getId().equals(sourceNode.getId())) { return Response.status(Status.BAD_REQUEST).entity("Circular copy reference").build(); } node = node.getParent(); } // Copy WorkspaceNode createdNode = null; WorkspaceMaterial createdMaterial = null; if (copyOnlyChildren) { List<WorkspaceNode> sourceChildren = workspaceMaterialController.listWorkspaceNodesByParent(sourceNode); for (WorkspaceNode sourceChild : sourceChildren) { workspaceMaterialController.cloneWorkspaceNode(sourceChild, targetNode, cloneMaterials); } } else { createdNode = workspaceMaterialController.cloneWorkspaceNode(sourceNode, targetNode, cloneMaterials); if (createdNode.getType() == WorkspaceNodeType.MATERIAL) { createdMaterial = workspaceMaterialController.findWorkspaceMaterialById(createdNode.getId()); if (entity != null && entity.getNextSiblingId() != null) { WorkspaceNode nextSibling = workspaceMaterialController.findWorkspaceNodeById(entity.getNextSiblingId()); if (nextSibling == null) { return Response.status(Status.BAD_REQUEST).entity("Specified next sibling does not exist").build(); } workspaceMaterialController.moveAbove(createdNode, nextSibling); } } } // Done return createdMaterial == null ? Response.noContent().build() : Response.ok(createRestModel(createdMaterial)).build(); } else { if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } if (entity.getMaterialId() == null) { return Response.status(Status.BAD_REQUEST).entity("material_id is required when creating new WorkspaceMaterial").build(); } WorkspaceNode parent = null; if (entity.getParentId() != null) { parent = workspaceMaterialController.findWorkspaceNodeById(entity.getParentId()); if (parent == null) { return Response.status(Status.NOT_FOUND).entity("parent not found").build(); } } else { parent = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceEntity(workspaceEntity); } Material material = materialController.findMaterialById(entity.getMaterialId()); if (material == null) { return Response.status(Status.NOT_FOUND).entity("material not found").build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.createWorkspaceMaterial(parent, material, entity.getAssignmentType(), entity.getCorrectAnswers()); if (entity.getNextSiblingId() != null) { WorkspaceNode nextSibling = workspaceMaterialController.findWorkspaceNodeById(entity.getNextSiblingId()); if (nextSibling == null) { return Response.status(Status.BAD_REQUEST).entity("Specified next sibling does not exist").build(); } if (!nextSibling.getParent().getId().equals(parent.getId())) { return Response.status(Status.BAD_REQUEST).entity("Specified next sibling does not share parent with created workspace material") .build(); } workspaceMaterialController.moveAbove(workspaceMaterial, nextSibling); } // #1261: HtmlMaterial attachments should be added to all workspace materials sharing the same HtmlMaterial if (updateLinkedMaterials && parent instanceof WorkspaceMaterial) { Long parentMaterialId = ((WorkspaceMaterial) parent).getMaterialId(); if (parentMaterialId != null) { Material parentMaterial = materialController.findMaterialById(parentMaterialId); if (parentMaterial instanceof HtmlMaterial) { List<WorkspaceMaterial> sharedWorkspaceMaterials = workspaceMaterialController.listWorkspaceMaterialsByMaterial(parentMaterial); for (WorkspaceMaterial sharedWorkspaceMaterial : sharedWorkspaceMaterials) { if (sharedWorkspaceMaterial.getId().equals(workspaceMaterial.getId())) { continue; // skip the one we created above } WorkspaceMaterial sharedAttachment = workspaceMaterialController.findWorkspaceMaterialByParentAndUrlName(sharedWorkspaceMaterial, workspaceMaterial.getUrlName()); if (sharedAttachment == null) { workspaceMaterialController.createWorkspaceMaterial( sharedWorkspaceMaterial, material, workspaceMaterial.getUrlName(), workspaceMaterial.getAssignmentType(), workspaceMaterial.getCorrectAnswers()); } } } } } return Response.ok(createRestModel(workspaceMaterial)).build(); } } @GET @Path("/workspaces/{WORKSPACEENTITYID}/materials/") @RESTPermitUnimplemented public Response listWorkspaceMaterials(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @QueryParam("parentId") Long parentId, @QueryParam ("assignmentType") String assignmentType) { // TODO: SecuritY??? if (parentId == null && assignmentType == null) { return Response.status(Status.NOT_IMPLEMENTED).entity("Listing workspace materials without parentId or assignmentType is currently not implemented").build(); } WorkspaceMaterialAssignmentType workspaceAssignmentType = null; if (assignmentType != null) { workspaceAssignmentType = WorkspaceMaterialAssignmentType.valueOf(assignmentType); if (workspaceAssignmentType == null) { return Response.status(Status.BAD_REQUEST).entity("Invalid assignmentType parameter").build(); } } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity("Could not find a workspace entity").build(); } List<WorkspaceMaterial> workspaceMaterials = null; if (parentId != null) { WorkspaceNode parent = workspaceMaterialController.findWorkspaceNodeById(parentId); if (parent == null) { return Response.status(Status.BAD_REQUEST).entity("Given workspace parent material does not exist").build(); } WorkspaceRootFolder rootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(parent); if (rootFolder == null) { return Response.status(Status.BAD_REQUEST).entity("Could not find a workspace root folder").build(); } if (!rootFolder.getWorkspaceEntityId().equals(workspaceEntityId)) { return Response.status(Status.BAD_REQUEST).entity("Invalid parentId").build(); } if (assignmentType != null) { // TODO: support for invisible materials workspaceMaterials = workspaceMaterialController.listVisibleWorkspaceMaterialsByParentAndAssignmentType(parent, workspaceEntity, workspaceAssignmentType); } else { workspaceMaterials = workspaceMaterialController.listWorkspaceMaterialsByParent(parent); } } else { // TODO: support for invisible materials workspaceMaterials = workspaceMaterialController.listVisibleWorkspaceMaterialsByAssignmentType(workspaceEntity, workspaceAssignmentType); } if (workspaceMaterials.isEmpty()) { return Response.noContent().build(); } return Response.ok(createRestModel(workspaceMaterials.toArray(new WorkspaceMaterial[0]))).build(); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/materials/{ID}") @RESTPermitUnimplemented public Response getWorkspaceMaterial(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("ID") Long workspaceMaterialId) { // TODO: Security WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).entity("workspaceMaterial not found").build(); } WorkspaceRootFolder rootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (rootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } if (!workspaceEntity.getId().equals(rootFolder.getWorkspaceEntityId())) { return Response.status(Status.NOT_FOUND).build(); } return Response.ok(createRestModel(workspaceMaterial)).build(); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/compositeReplies") @RESTPermitUnimplemented public Response getWorkspaceMaterialAnswers(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId) { // TODO: Correct workspace entity? // TODO: Available to all logged-in users? if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } List<WorkspaceCompositeReply> result = new ArrayList<>(); WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity("Workspace could not be found").build(); } try { List<fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply> replies = workspaceMaterialReplyController.listVisibleWorkspaceMaterialRepliesByWorkspaceEntity(workspaceEntity, sessionController.getLoggedUserEntity()); for (fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply reply : replies) { List<WorkspaceMaterialFieldAnswer> answers = new ArrayList<>(); List<WorkspaceMaterialField> fields = workspaceMaterialFieldController.listWorkspaceMaterialFieldsByWorkspaceMaterial(reply.getWorkspaceMaterial()); for (WorkspaceMaterialField field : fields) { String value = workspaceMaterialFieldController.retrieveFieldValue(field, reply); Material material = field.getQueryField().getMaterial(); WorkspaceMaterialFieldAnswer answer = new WorkspaceMaterialFieldAnswer(reply.getWorkspaceMaterial().getId(), material.getId(), field.getEmbedId(), field.getQueryField().getName(), value); answers.add(answer); } result.add(new WorkspaceCompositeReply(reply.getWorkspaceMaterial().getId(), reply.getId(), reply.getState(), answers)); } if (result.isEmpty()) { return Response.noContent().build(); } } catch (WorkspaceFieldIOException e) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Internal error occurred while retrieving field answers: " + e.getMessage()).build(); } CacheControl cacheControl = new CacheControl(); cacheControl.setMustRevalidate(true); cacheControl.setNoCache(true); cacheControl.setProxyRevalidate(true); return Response .ok(result) .cacheControl(cacheControl) .build(); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/materials/{WORKSPACEMATERIALID}/compositeMaterialReplies") @RESTPermitUnimplemented public Response getWorkspaceMaterialAnswers(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, @QueryParam ("userEntityId") Long userEntityId) { // TODO: Correct workspace entity?, // TODO: Security if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } // TODO Return everyone's answers if (userEntityId == null) { return Response.status(Status.NOT_IMPLEMENTED).build(); } UserEntity userEntity = userEntityController.findUserEntityById(userEntityId); WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).entity("Workspace material could not be found").build(); } List<WorkspaceMaterialFieldAnswer> answers = new ArrayList<>(); try { fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply reply = workspaceMaterialReplyController.findWorkspaceMaterialReplyByWorkspaceMaterialAndUserEntity(workspaceMaterial, userEntity); if (reply != null) { List<WorkspaceMaterialField> fields = workspaceMaterialFieldController.listWorkspaceMaterialFieldsByWorkspaceMaterial(workspaceMaterial); for (WorkspaceMaterialField field : fields) { String value = workspaceMaterialFieldController.retrieveFieldValue(field, reply); Material material = field.getQueryField().getMaterial(); WorkspaceMaterialFieldAnswer answer = new WorkspaceMaterialFieldAnswer(workspaceMaterial.getId(), material.getId(), field.getEmbedId(), field.getQueryField().getName(), value); answers.add(answer); } } WorkspaceMaterialCompositeReply result = new WorkspaceMaterialCompositeReply(answers, reply != null ? reply.getState() : null, reply != null ? reply.getCreated() : null, reply != null ? reply.getLastModified() : null, reply != null ? reply.getSubmitted() : null, reply != null ? reply.getWithdrawn() : null ); return Response.ok(result).build(); } catch (WorkspaceFieldIOException e) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Internal error occurred while retrieving field answers: " + e.getMessage()).build(); } } @GET @Path("/fileanswer/{FILEID}") @RESTPermit (handling = Handling.INLINE) public Response getFileAnswer(@PathParam("FILEID") String fileId) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceMaterialFileFieldAnswerFile answerFile = workspaceMaterialFieldAnswerController.findWorkspaceMaterialFileFieldAnswerFileByFileId(fileId); if (answerFile != null) { fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply workspaceMaterialReply = answerFile.getFieldAnswer().getReply(); if (workspaceMaterialReply == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find reply from answer file %d", answerFile.getId())) .build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialReply.getWorkspaceMaterial(); if (workspaceMaterial == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace material from reply %d", workspaceMaterialReply.getId())) .build(); } WorkspaceRootFolder workspaceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (workspaceRootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace root folder for material %d", workspaceMaterial.getId())) .build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceRootFolder.getWorkspaceEntityId()); if (workspaceEntity == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace entity for root folder %d", workspaceRootFolder.getId())) .build(); } if (!workspaceMaterialReply.getUserEntityId().equals(sessionController.getLoggedUserEntity().getId())) { if (!sessionController.hasWorkspacePermission(MuikkuPermissions.ACCESS_STUDENT_ANSWERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } } return Response.ok(answerFile.getContent()) .type(answerFile.getContentType()) .header("Content-Disposition", "attachment; filename=\"" + answerFile.getFileName().replaceAll("\"", "\\\"") + "\"") .build(); } return Response.status(Status.NOT_FOUND).build(); } @GET @Path("/audioanswer/{CLIPID}") @RESTPermit (handling = Handling.INLINE) public Response getAudioAnswer(@PathParam("CLIPID") String clipId) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceMaterialAudioFieldAnswerClip answerClip = workspaceMaterialFieldAnswerController.findWorkspaceMaterialAudioFieldAnswerClipByClipId(clipId); if (answerClip != null) { fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply workspaceMaterialReply = answerClip.getFieldAnswer().getReply(); if (workspaceMaterialReply == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find reply from answer audio %d", answerClip.getId())) .build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialReply.getWorkspaceMaterial(); if (workspaceMaterial == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace material from reply %d", workspaceMaterialReply.getId())) .build(); } WorkspaceRootFolder workspaceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (workspaceRootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace root folder for material %d", workspaceMaterial.getId())) .build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceRootFolder.getWorkspaceEntityId()); if (workspaceEntity == null) { return Response.status(Status.INTERNAL_SERVER_ERROR) .entity(String.format("Could not find workspace entity for root folder %d", workspaceRootFolder.getId())) .build(); } if (!workspaceMaterialReply.getUserEntityId().equals(sessionController.getLoggedUserEntity().getId())) { if (!sessionController.hasWorkspacePermission(MuikkuPermissions.ACCESS_STUDENT_ANSWERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } } return Response.ok(answerClip.getContent()) .type(answerClip.getContentType()) .header("Content-Disposition", "attachment; filename=\"" + answerClip.getFileName().replaceAll("\"", "\\\"") + "\"") .build(); } return Response.status(Status.NOT_FOUND).build(); } @GET // @Path ("/workspaces/{WORKSPACEENTITYID:[0-9]*}/materials/{WORKSPACEMATERIALID:[0-9]*}/replies") @Path ("/workspaces/{WORKSPACEENTITYID}/materials/{WORKSPACEMATERIALID}/replies") @RESTPermitUnimplemented public Response listWorkspaceMaterialReplies(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, @QueryParam ("userEntityId") Long userEntityId) { // TODO: Security! if (userEntityId == null) { return Response.status(Status.NOT_IMPLEMENTED).entity("Currently listing must be filtered by userEntityId").build(); } UserEntity loggedUser = sessionController.getLoggedUserEntity(); if (loggedUser == null) { return Response.status(Status.UNAUTHORIZED).entity("Unauthorized").build(); } if (!userEntityId.equals(loggedUser.getId())) { return Response.status(Status.UNAUTHORIZED).entity("Not permitted to list another user's replies").build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace entity").build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace material").build(); } WorkspaceRootFolder workspaceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (workspaceRootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not find workspace root folder").build(); } if (!workspaceRootFolder.getWorkspaceEntityId().equals(workspaceEntity.getId())) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace material id or workspace entity id").build(); } fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply materialReply = workspaceMaterialReplyController.findWorkspaceMaterialReplyByWorkspaceMaterialAndUserEntity(workspaceMaterial, loggedUser); if (materialReply != null) { return Response.ok(createRestModel(new fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply[] { materialReply })).build(); } else { return Response.ok(createRestModel(new fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply[] { })).build(); } } @POST // @Path ("/workspaces/{WORKSPACEENTITYID:[0-9]*}/materials/{WORKSPACEMATERIALID:[0-9]*}/replies") @Path ("/workspaces/{WORKSPACEENTITYID}/materials/{WORKSPACEMATERIALID}/replies") @RESTPermitUnimplemented public Response createWorkspaceMaterialReply(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, WorkspaceMaterialReply payload) { // TODO: Security! if (payload == null) { return Response.status(Status.BAD_REQUEST).entity("Payload is missing").build(); } if (payload.getState() == null) { return Response.status(Status.BAD_REQUEST).entity("State is missing").build(); } UserEntity loggedUser = sessionController.getLoggedUserEntity(); if (loggedUser == null) { return Response.status(Status.UNAUTHORIZED).entity("Unauthorized").build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace entity").build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace material").build(); } WorkspaceRootFolder workspaceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (workspaceRootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not find workspace root folder").build(); } if (!workspaceRootFolder.getWorkspaceEntityId().equals(workspaceEntity.getId())) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace material id or workspace entity id").build(); } fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply workspaceMaterialReply = workspaceMaterialReplyController.createWorkspaceMaterialReply(workspaceMaterial, payload.getState(), loggedUser); return Response.ok(createRestModel(workspaceMaterialReply)).build(); } @PUT // @Path ("/workspaces/{WORKSPACEENTITYID:[0-9]*}/materials/{WORKSPACEMATERIALID:[0-9]*}/replies/{REPLYID:[0-9]*}") @Path ("/workspaces/{WORKSPACEENTITYID}/materials/{WORKSPACEMATERIALID}/replies/{REPLYID}") @RESTPermitUnimplemented public Response createWorkspaceMaterialReply(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, @PathParam ("REPLYID") Long workspaceMaterialReplyId, WorkspaceMaterialReply payload) { // TODO: Security! if (payload == null) { return Response.status(Status.BAD_REQUEST).entity("Payload is missing").build(); } UserEntity loggedUser = sessionController.getLoggedUserEntity(); if (loggedUser == null) { return Response.status(Status.UNAUTHORIZED).entity("Unauthorized").build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace entity").build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace material").build(); } WorkspaceRootFolder workspaceRootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceNode(workspaceMaterial); if (workspaceRootFolder == null) { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not find workspace root folder").build(); } if (!workspaceRootFolder.getWorkspaceEntityId().equals(workspaceEntity.getId())) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace material id or workspace entity id").build(); } fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply workspaceMaterialReply = workspaceMaterialReplyController.findWorkspaceMaterialReplyById(workspaceMaterialReplyId); if (workspaceMaterialReply == null) { return Response.status(Status.NOT_FOUND).entity("Could not find workspace material reply").build(); } workspaceMaterialReplyController.updateWorkspaceMaterialReply(workspaceMaterialReply, payload.getState()); return Response.noContent().build(); } private List<fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialProducer> createRestModel(WorkspaceMaterialProducer... materialProducers) { List<fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialProducer> result = new ArrayList<>(); for (WorkspaceMaterialProducer materialProducer : materialProducers) { result.add(createRestModel(materialProducer)); } return result; } private fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialProducer createRestModel(WorkspaceMaterialProducer materialProducer) { return new fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialProducer(materialProducer.getId(), materialProducer.getWorkspaceEntity().getId(), materialProducer.getName()); } private List<fi.otavanopisto.muikku.plugins.workspace.rest.WorkspaceType> createRestModel(WorkspaceType... types) { List<fi.otavanopisto.muikku.plugins.workspace.rest.WorkspaceType> result = new ArrayList<>(); for (WorkspaceType type : types) { result.add(new fi.otavanopisto.muikku.plugins.workspace.rest.WorkspaceType(type.getIdentifier().toId(), type.getName())); } return result; } private List<fi.otavanopisto.muikku.plugins.workspace.rest.EducationType> createRestModel(EducationType... types) { List<fi.otavanopisto.muikku.plugins.workspace.rest.EducationType> result = new ArrayList<>(); for (EducationType type : types) { result.add(new fi.otavanopisto.muikku.plugins.workspace.rest.EducationType(type.getIdentifier().toId(), type.getName())); } return result; } private List<WorkspaceMaterialReply> createRestModel(fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply... entries) { List<fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterialReply> result = new ArrayList<>(); for (fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply entry : entries) { result.add(createRestModel(entry)); } return result; } private WorkspaceMaterialReply createRestModel(fi.otavanopisto.muikku.plugins.workspace.model.WorkspaceMaterialReply entity) { return new WorkspaceMaterialReply(entity.getId(), entity.getState()); } private List<fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial> createRestModel(WorkspaceMaterial... entries) { List<fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial> result = new ArrayList<>(); for (WorkspaceMaterial entry : entries) { result.add(createRestModel(entry)); } return result; } private fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial createRestModel(WorkspaceMaterial workspaceMaterial) { WorkspaceNode workspaceNode = workspaceMaterialController.findWorkspaceNodeNextSibling(workspaceMaterial); Long nextSiblingId = workspaceNode != null ? workspaceNode.getId() : null; return new fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial(workspaceMaterial.getId(), workspaceMaterial.getMaterialId(), workspaceMaterial.getParent() != null ? workspaceMaterial.getParent().getId() : null, nextSiblingId, workspaceMaterial.getHidden(), workspaceMaterial.getAssignmentType(), workspaceMaterial.getCorrectAnswers(), workspaceMaterial.getPath(), workspaceMaterial.getTitle()); } private fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace createRestModel(WorkspaceEntity workspaceEntity, String name, String nameExtension, String description, Set<String> curriculumIdentifiers) { Long numVisits = workspaceVisitController.getNumVisits(workspaceEntity); Date lastVisit = workspaceVisitController.getLastVisit(workspaceEntity); return new fi.otavanopisto.muikku.plugins.workspace.rest.model.Workspace(workspaceEntity.getId(), workspaceEntity.getUrlName(), workspaceEntity.getAccess(), workspaceEntity.getArchived(), workspaceEntity.getPublished(), name, nameExtension, description, workspaceEntity.getDefaultMaterialLicense(), numVisits, lastVisit, curriculumIdentifiers); } private fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceFolder createRestModel(WorkspaceFolder workspaceFolder) { WorkspaceNode nextSibling = workspaceMaterialController.findWorkspaceNodeNextSibling(workspaceFolder); return new fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceFolder( workspaceFolder.getId(), workspaceFolder.getParent() == null ? null : workspaceFolder.getParent().getId(), nextSibling == null ? null : nextSibling.getId(), workspaceFolder.getHidden(), workspaceFolder.getTitle(), workspaceFolder.getPath(), workspaceFolder.getViewRestrict()); } @DELETE @Path("/workspaces/{WORKSPACEID}/materials/{WORKSPACEMATERIALID}") @RESTPermitUnimplemented public Response deleteNode( @PathParam("WORKSPACEID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, @QueryParam("removeAnswers") Boolean removeAnswers, @QueryParam("updateLinkedMaterials") @DefaultValue ("false") Boolean updateLinkedMaterials) { // TODO Our workspace? if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } WorkspaceEntity workspaceEntity = workspaceEntityController.findWorkspaceEntityById(workspaceEntityId); if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceMaterial workspaceMaterial = workspaceMaterialController.findWorkspaceMaterialById(workspaceMaterialId); if (workspaceMaterial == null) { return Response.status(Status.NOT_FOUND).build(); } else { try { // #1261: HtmlMaterial attachments should be removed from all workspace materials sharing the same HtmlMaterial if (updateLinkedMaterials) { WorkspaceNode parentNode = workspaceMaterial.getParent(); if (parentNode instanceof WorkspaceMaterial) { Long parentMaterialId = ((WorkspaceMaterial) parentNode).getMaterialId(); if (parentMaterialId != null) { Material parentMaterial = materialController.findMaterialById(parentMaterialId); if (parentMaterial instanceof HtmlMaterial) { List<WorkspaceMaterial> sharedWorkspaceMaterials = workspaceMaterialController.listWorkspaceMaterialsByMaterial(parentMaterial); for (WorkspaceMaterial sharedWorkspaceMaterial : sharedWorkspaceMaterials) { WorkspaceMaterial childWorkspaceMaterial = workspaceMaterialController.findWorkspaceMaterialByParentAndUrlName(sharedWorkspaceMaterial, workspaceMaterial.getUrlName()); if (childWorkspaceMaterial.getId().equals(workspaceMaterial.getId())) { continue; // skip the one we delete below } workspaceMaterialController.deleteWorkspaceMaterial(childWorkspaceMaterial, removeAnswers != null ? removeAnswers : false); } } } } } workspaceMaterialController.deleteWorkspaceMaterial(workspaceMaterial, removeAnswers != null ? removeAnswers : false); return Response.noContent().build(); } catch (WorkspaceMaterialContainsAnswersExeption e) { return Response.status(Status.CONFLICT).entity(new WorkspaceMaterialDeleteError(WorkspaceMaterialDeleteError.Reason.CONTAINS_ANSWERS)).build(); } catch (Exception e) { return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } } } @GET @Path("/workspaces/{WORKSPACEID}/folders/{WORKSPACEFOLDERID}") @RESTPermitUnimplemented public Response getWorkspaceFolder( @PathParam("WORKSPACEID") Long workspaceEntityId, @PathParam("WORKSPACEFOLDERID") Long workspaceFolderId) { // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } // WorkspaceFolder WorkspaceFolder workspaceFolder = workspaceMaterialController.findWorkspaceFolderById(workspaceFolderId); if (workspaceFolder == null) { return Response.status(Status.NOT_FOUND).build(); } return Response.ok(createRestModel(workspaceFolder)).build(); } @DELETE @Path("/workspaces/{WORKSPACEID}/folders/{WORKSPACEFOLDERID}") @RESTPermitUnimplemented public Response deleteWorkspaceFolder( @PathParam("WORKSPACEID") Long workspaceEntityId, @PathParam("WORKSPACEFOLDERID") Long workspaceFolderId) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } // WorkspaceFolder WorkspaceFolder workspaceFolder = workspaceMaterialController.findWorkspaceFolderById(workspaceFolderId); if (workspaceFolder != null) { workspaceMaterialController.deleteWorkspaceFolder(workspaceFolder); } return Response.ok(createRestModel(workspaceFolder)).build(); } @PUT @Path("/workspaces/{WORKSPACEID}/folders/{WORKSPACEFOLDERID}") @RESTPermitUnimplemented public Response updateWorkspaceFolder( @PathParam("WORKSPACEID") Long workspaceEntityId, @PathParam("WORKSPACEFOLDERID") Long workspaceFolderId, fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceFolder restFolder) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } if (restFolder == null) { return Response.status(Status.BAD_REQUEST).build(); } // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } // WorkspaceFolder WorkspaceFolder workspaceFolder = workspaceMaterialController.findWorkspaceFolderById(restFolder.getId()); if (workspaceFolder == null) { return Response.status(Status.BAD_REQUEST).build(); } // Workspace folder belongs to workspace check Long folderWorkspaceEntityId = workspaceMaterialController.getWorkspaceEntityId(workspaceFolder); if (!folderWorkspaceEntityId.equals(workspaceEntityId)) { return Response.status(Status.BAD_REQUEST).build(); } // Actual update WorkspaceNode parentNode = restFolder.getParentId() == null ? null : workspaceMaterialController.findWorkspaceNodeById(restFolder.getParentId()); WorkspaceNode nextSibling = restFolder.getNextSiblingId() == null ? null : workspaceMaterialController.findWorkspaceNodeById(restFolder.getNextSiblingId()); Boolean hidden = restFolder.getHidden(); String title = restFolder.getTitle(); MaterialViewRestrict viewRestrict = restFolder.getViewRestrict(); workspaceFolder = workspaceMaterialController.updateWorkspaceFolder(workspaceFolder, title, parentNode, nextSibling, hidden, viewRestrict); return Response.ok(createRestModel(workspaceFolder)).build(); } @POST @Path("/workspaces/{WORKSPACEID}/folders/") @RESTPermitUnimplemented public Response createWorkspaceFolder( @PathParam("WORKSPACEID") Long workspaceEntityId, fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceFolder restFolder) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } if (restFolder == null) { return Response.status(Status.BAD_REQUEST).build(); } // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceNode rootFolder = workspaceMaterialController.findWorkspaceRootFolderByWorkspaceEntity(workspaceEntity); WorkspaceNode nextSibling = restFolder.getNextSiblingId() == null ? null : workspaceMaterialController.findWorkspaceNodeById(restFolder.getNextSiblingId()); WorkspaceFolder workspaceFolder = workspaceMaterialController.createWorkspaceFolder(rootFolder, "Untitled"); if (nextSibling != null) { workspaceMaterialController.moveAbove(workspaceFolder, nextSibling); } return Response.ok(createRestModel(workspaceFolder)).build(); } @PUT @Path("/workspaces/{WORKSPACEID}/materials/{WORKSPACEMATERIALID}") @RESTPermitUnimplemented // TODO @LoggedIn public Response updateWorkspaceMaterial(@PathParam("WORKSPACEID") Long workspaceEntityId, @PathParam("WORKSPACEMATERIALID") Long workspaceMaterialId, fi.otavanopisto.muikku.plugins.workspace.rest.model.WorkspaceMaterial workspaceMaterial) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MATERIALS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } // WorkspaceNode WorkspaceNode workspaceNode = workspaceMaterialController.findWorkspaceNodeById(workspaceMaterial.getId()); if (workspaceNode == null) { return Response.status(Status.BAD_REQUEST).build(); } // Workspace material belongs to workspace check Long materialWorkspaceEntityId = workspaceMaterialController.getWorkspaceEntityId(workspaceNode); if (!materialWorkspaceEntityId.equals(workspaceEntityId)) { return Response.status(Status.BAD_REQUEST).build(); } // Actual update Long materialId = workspaceMaterial.getMaterialId(); WorkspaceNode parentNode = workspaceMaterialController.findWorkspaceNodeById(workspaceMaterial.getParentId()); WorkspaceNode nextSibling = workspaceMaterial.getNextSiblingId() == null ? null : workspaceMaterialController.findWorkspaceNodeById(workspaceMaterial.getNextSiblingId()); String title = workspaceMaterial.getTitle(); Boolean hidden = workspaceMaterial.getHidden(); workspaceNode = workspaceMaterialController.updateWorkspaceNode(workspaceNode, materialId, parentNode, nextSibling, hidden, workspaceMaterial.getAssignmentType(), workspaceMaterial.getCorrectAnswers(), title); workspaceMaterial.setPath(workspaceNode.getPath()); return Response.ok(workspaceMaterial).build(); } @GET @Path("/workspaces/{WORKSPACEENTITYID}/students/{ID}") @RESTPermit(handling = Handling.INLINE) public Response findWorkspaceStudent(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("ID") String workspaceStudentId) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } SchoolDataIdentifier workspaceUserIdentifier = SchoolDataIdentifier.fromId(workspaceStudentId); if (workspaceUserIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace user id").build(); } WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityController.findWorkspaceUserEntityByWorkspaceUserIdentifierIncludeArchived(workspaceUserIdentifier); if (workspaceUserEntity == null) { return Response.status(Status.NOT_FOUND).entity("Workspace student not found").build(); } fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser bridgeUser = workspaceController.findWorkspaceUser(workspaceUserEntity); if (bridgeUser == null) { return Response.status(Status.NOT_FOUND).entity("School data user not found").build(); } SchoolDataIdentifier userIdentifier = bridgeUser.getUserIdentifier(); User user = userController.findUserByIdentifier(userIdentifier); if (user == null) { return Response.status(Status.NOT_FOUND).entity("School data user not found").build(); } WorkspaceUser workspaceUser = workspaceController.findWorkspaceUserByWorkspaceEntityAndUser(workspaceEntity, userIdentifier); if (workspaceUser == null) { return Response.status(Status.NOT_FOUND).entity("School data workspace user not found").build(); } return Response.ok(createRestModel(workspaceUserEntity.getUserSchoolDataIdentifier().getUserEntity(), user, workspaceUser, workspaceUserEntity.getArchived())).build(); } @PUT @Path("/workspaces/{WORKSPACEENTITYID}/students/{ID}") @RESTPermit(handling = Handling.INLINE) public Response updateWorkspaceStudent(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("ID") String workspaceStudentId, WorkspaceStudent workspaceStudent) { // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } // Access check if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MEMBERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } // Workspace student and school data user SchoolDataIdentifier workspaceUserIdentifier = SchoolDataIdentifier.fromId(workspaceStudentId); if (workspaceUserIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace user id").build(); } SchoolDataIdentifier workspaceIdentifier = new SchoolDataIdentifier(workspaceEntity.getIdentifier(), workspaceEntity.getDataSource().getIdentifier()); fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser bridgeUser = workspaceController.findWorkspaceUser(workspaceIdentifier, workspaceUserIdentifier); if (bridgeUser == null) { return Response.status(Status.NOT_FOUND).entity("School data user not found").build(); } if (workspaceStudent.getArchived() != null) { workspaceController.updateWorkspaceStudentActivity(bridgeUser, !workspaceStudent.getArchived()); WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityController.findWorkspaceUserEntityByWorkspaceUserIdentifierIncludeArchived(workspaceUserIdentifier); if (workspaceStudent.getArchived()) { // Archive if (workspaceUserEntity != null && !workspaceUserEntity.getArchived()) { workspaceUserEntityController.archiveWorkspaceUserEntity(workspaceUserEntity); } } else { // Unarchive if (workspaceUserEntity == null) { // TODO create new workspace student } else { workspaceUserEntityController.unarchiveWorkspaceUserEntity(workspaceUserEntity); } } } return Response.ok(workspaceStudent).build(); } @DELETE @Path("/workspaces/{WORKSPACEENTITYID}/students/{ID}") @RESTPermit (handling = Handling.INLINE) public Response deleteWorkspaceStudent(@PathParam("WORKSPACEENTITYID") Long workspaceEntityId, @PathParam("ID") String workspaceStudentId) { // Workspace WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.BAD_REQUEST).build(); } // User (in school data source) SchoolDataIdentifier workspaceUserIdentifier = SchoolDataIdentifier.fromId(workspaceStudentId); if (workspaceUserIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspace user id").build(); } // Access check if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).entity("Not logged in").build(); } if (!sessionController.hasWorkspacePermission(MuikkuPermissions.MANAGE_WORKSPACE_MEMBERS, workspaceEntity)) { return Response.status(Status.FORBIDDEN).build(); } WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityController.findWorkspaceUserEntityByWorkspaceUserIdentifier(workspaceUserIdentifier); if (workspaceUserEntity == null) { return Response.status(Status.NOT_FOUND).entity("Workspace student not found").build(); } fi.otavanopisto.muikku.schooldata.entity.WorkspaceUser bridgeUser = workspaceController.findWorkspaceUser(workspaceUserEntity); if (bridgeUser == null) { return Response.status(Status.NOT_FOUND).entity("School data user not found").build(); } workspaceController.updateWorkspaceStudentActivity(bridgeUser, false); workspaceUserEntityController.archiveWorkspaceUserEntity(workspaceUserEntity); return Response.noContent().build(); } @GET @Path("/workspaces/{WORKSPACEID}/journal") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response listJournalEntries( @PathParam("WORKSPACEID") Long workspaceEntityId, @QueryParam("userEntityId") Long userEntityId, @QueryParam("workspaceStudentId") String workspaceStudentId, @QueryParam("firstResult") @DefaultValue ("0") Integer firstResult, @QueryParam("maxResults") @DefaultValue ("25") Integer maxResults) { // Workspace List<WorkspaceJournalEntry> entries = new ArrayList<>(); List<WorkspaceJournalEntryRESTModel> result = new ArrayList<>(); WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } UserEntity userEntity = sessionController.getLoggedUserEntity(); boolean canListAllEntries = sessionController.hasWorkspacePermission(MuikkuPermissions.LIST_ALL_JOURNAL_ENTRIES, workspaceEntity); if (workspaceStudentId == null && userEntityId == null && canListAllEntries) { entries = workspaceJournalController.listEntries(workspaceEntity, firstResult, maxResults); } else { if (userEntityId != null) { // List by user entity (Muikku) if (!userEntityId.equals(userEntity.getId())) { if (canListAllEntries) { userEntity = userEntityController.findUserEntityById(userEntityId); if (userEntity == null) { return Response.status(Status.NOT_FOUND).build(); } } else { return Response.status(Status.FORBIDDEN).build(); } } } else if (workspaceStudentId != null) { // List by workspace student (school data) SchoolDataIdentifier workspaceUserIdentifier = SchoolDataIdentifier.fromId(workspaceStudentId); if (workspaceUserIdentifier == null) { return Response.status(Status.BAD_REQUEST).entity("Invalid workspaceStudentId").build(); } WorkspaceUserEntity workspaceUserEntity = workspaceUserEntityController.findWorkspaceUserEntityByWorkspaceUserIdentifierIncludeArchived(workspaceUserIdentifier); if (workspaceUserEntity == null) { return Response.status(Status.NOT_FOUND).build(); } UserSchoolDataIdentifier userSchoolDataIdentifier = workspaceUserEntity.getUserSchoolDataIdentifier(); UserEntity userEntityFromWorkspaceUser = userEntityController.findUserEntityByDataSourceAndIdentifier( userSchoolDataIdentifier.getDataSource(), userSchoolDataIdentifier.getIdentifier()); if (userEntityFromWorkspaceUser == null) { return Response.status(Status.NOT_FOUND).build(); } if (!canListAllEntries) { if (!userEntity.getId().equals(userEntityFromWorkspaceUser.getId())) { return Response.status(Status.FORBIDDEN).build(); } } else { userEntity = userEntityFromWorkspaceUser; } } entries = workspaceJournalController.listEntriesByWorkspaceEntityAndUserEntity(workspaceEntity, userEntity, firstResult, maxResults); } for (WorkspaceJournalEntry entry : entries) { UserEntity entryUserEntity = userEntityController.findUserEntityById(entry.getUserEntityId()); User user = userController.findUserByUserEntityDefaults(entryUserEntity); result.add(new WorkspaceJournalEntryRESTModel( entry.getId(), entry.getWorkspaceEntityId(), entry.getUserEntityId(), user.getFirstName(), user.getLastName(), entry.getHtml(), entry.getTitle(), entry.getCreated() )); } return Response.ok(result).build(); } @POST @Path("/workspaces/{WORKSPACEID}/journal") @RESTPermitUnimplemented public Response addJournalEntry(@PathParam("WORKSPACEID") Long workspaceEntityId, WorkspaceJournalEntryRESTModel restModel) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceEntity workspaceEntity = workspaceController.findWorkspaceEntityById(workspaceEntityId); if (workspaceEntity == null) { return Response.status(Status.NOT_FOUND).build(); } workspaceJournalController.createJournalEntry( workspaceController.findWorkspaceEntityById(workspaceEntityId), sessionController.getLoggedUserEntity(), restModel.getContent(), restModel.getTitle()); return Response.noContent().build(); } @PUT @Path("/journal/{JOURNALENTRYID}") @RESTPermitUnimplemented public Response updateJournalEntry(@PathParam("JOURNALENTRYID") Long journalEntryId, WorkspaceJournalEntryRESTModel restModel) { if (!sessionController.isLoggedIn()) { return Response.status(Status.UNAUTHORIZED).build(); } WorkspaceJournalEntry workspaceJournalEntry = workspaceJournalController.findJournalEntry(journalEntryId); if (workspaceJournalEntry == null) { return Response.status(Status.NOT_FOUND).build(); } workspaceJournalController.updateJournalEntry( journalEntryId, restModel.getTitle(), restModel.getContent()); return Response.noContent().build(); } @DELETE @Path("/workspaces/{WORKSPACEID}/journal/{JOURNALENTRYID}") @RESTPermit (handling = Handling.INLINE, requireLoggedIn = true) public Response updateJournalEntry(@PathParam("WORKSPACEID") Integer workspaceId, @PathParam("JOURNALENTRYID") Long journalEntryId) { WorkspaceJournalEntry workspaceJournalEntry = workspaceJournalController.findJournalEntry(journalEntryId); if (workspaceJournalEntry == null) { return Response.status(Status.NOT_FOUND).build(); } if (!workspaceJournalEntry.getUserEntityId().equals(sessionController.getLoggedUserEntity().getId())) { return Response.status(Status.FORBIDDEN).build(); } workspaceJournalController.archiveJournalEntry(workspaceJournalEntry); return Response.noContent().build(); } }