/* * This file is part of ARSnova Backend. * Copyright (C) 2012-2018 The ARSnova Team and Contributors * * ARSnova Backend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ARSnova Backend is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.thm.arsnova.controller.v2; import de.thm.arsnova.controller.PaginationController; import de.thm.arsnova.entities.migration.FromV2Migrator; import de.thm.arsnova.entities.migration.ToV2Migrator; import de.thm.arsnova.entities.migration.v2.Room; import de.thm.arsnova.entities.migration.v2.RoomFeature; import de.thm.arsnova.entities.transport.ImportExportContainer; import de.thm.arsnova.entities.transport.ScoreStatistics; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.services.RoomService; import de.thm.arsnova.services.RoomServiceImpl; import de.thm.arsnova.services.RoomServiceImpl.RoomNameComparator; import de.thm.arsnova.services.RoomServiceImpl.RoomShortNameComparator; import de.thm.arsnova.services.UserService; import de.thm.arsnova.web.DeprecatedApi; import de.thm.arsnova.web.Pagination; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * Handles requests related to ARSnova Rooms. */ @RestController("v2RoomController") @RequestMapping("/v2/session") @Api(value = "/session", description = "Room (Session) API") public class RoomController extends PaginationController { @Autowired private RoomService roomService; @Autowired private UserService userService; @Autowired private ToV2Migrator toV2Migrator; @Autowired private FromV2Migrator fromV2Migrator; @ApiOperation(value = "join a Room", nickname = "joinRoom") @DeprecatedApi @Deprecated @RequestMapping(value = "/{shortId}", method = RequestMethod.GET) public Room joinRoom( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "Adminflag", required = false) @RequestParam(value = "admin", defaultValue = "false") final boolean admin ) { if (admin) { return toV2Migrator.migrate(roomService.getForAdmin(shortId)); } else { return toV2Migrator.migrate(roomService.getByShortId(shortId)); } } @ApiOperation(value = "deletes a Room", nickname = "deleteRoom") @RequestMapping(value = "/{shortId}", method = RequestMethod.DELETE) public void deleteRoom(@ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId) { de.thm.arsnova.entities.Room room = roomService.getByShortId(shortId); roomService.deleteCascading(room); } @ApiOperation(value = "count active users", nickname = "countActiveUsers") @DeprecatedApi @Deprecated @RequestMapping(value = "/{shortId}/activeusercount", method = RequestMethod.GET) public int countActiveUsers(@ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId) { return roomService.activeUsers(shortId); } @ApiOperation(value = "Creates a new Room and returns the Room's data", nickname = "postNewRoom") @ApiResponses(value = { @ApiResponse(code = 201, message = HTML_STATUS_201), @ApiResponse(code = 503, message = HTML_STATUS_503) }) @RequestMapping(value = "/", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public Room postNewRoom(@ApiParam(value = "current Room", required = true) @RequestBody final Room room, final HttpServletResponse response) { /* FIXME: migrate LMS course support if (room != null && room.isCourseSession()) { final List<Course> courses = new ArrayList<>(); final Course course = new Course(); course.setId(room.getCourseId()); courses.add(course); final int sessionCount = roomService.countSessionsByCourses(courses); if (sessionCount > 0) { final String appendix = " (" + (sessionCount + 1) + ")"; room.setName(room.getName() + appendix); room.setAbbreviation(room.getAbbreviation() + appendix); } } */ return toV2Migrator.migrate(roomService.save(fromV2Migrator.migrate(room))); } @ApiOperation(value = "updates a Room", nickname = "postNewRoom") @RequestMapping(value = "/{shortId}", method = RequestMethod.PUT) public Room updateRoom( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "current room", required = true) @RequestBody final Room room ) { return toV2Migrator.migrate(roomService.update(shortId, fromV2Migrator.migrate(room))); } @ApiOperation(value = "change the Room creator (owner)", nickname = "changeRoomCreator") @RequestMapping(value = "/{shortId}/changecreator", method = RequestMethod.PUT) public Room changeRoomCreator( @ApiParam(value = "Room-key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "new Room creator", required = true) @RequestBody final String newCreator ) { return toV2Migrator.migrate(roomService.updateCreator(shortId, newCreator)); } @ApiOperation(value = "Retrieves a list of Rooms", nickname = "getRooms") @ApiResponses(value = { @ApiResponse(code = 204, message = HTML_STATUS_204), @ApiResponse(code = 501, message = HTML_STATUS_501) }) @RequestMapping(value = "/", method = RequestMethod.GET) @Pagination public List<Room> getRooms( @ApiParam(value = "ownedOnly", required = true) @RequestParam(value = "ownedonly", defaultValue = "false") final boolean ownedOnly, @ApiParam(value = "visitedOnly", required = true) @RequestParam(value = "visitedonly", defaultValue = "false") final boolean visitedOnly, @ApiParam(value = "sortby", required = true) @RequestParam(value = "sortby", defaultValue = "name") final String sortby, @ApiParam(value = "for a given username. admin rights needed", required = false) @RequestParam(value = "username", defaultValue = "") final String username, final HttpServletResponse response ) { List<de.thm.arsnova.entities.Room> rooms; if (!"".equals(username)) { final String userId = userService.getByUsername(username).getId(); try { if (ownedOnly && !visitedOnly) { rooms = roomService.getUserRooms(userId); } else if (visitedOnly && !ownedOnly) { rooms = roomService.getUserRoomHistory(username); } else { response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); return null; } } catch (final AccessDeniedException e) { throw new UnauthorizedException(); } } else { /* TODO implement all parameter combinations, implement use of user parameter */ try { if (ownedOnly && !visitedOnly) { rooms = roomService.getMyRooms(offset, limit); } else if (visitedOnly && !ownedOnly) { rooms = roomService.getMyRoomHistory(offset, limit); } else { response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); return null; } } catch (final AccessDeniedException e) { throw new UnauthorizedException(); } } if (rooms == null || rooms.isEmpty()) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return null; } if ("shortname".equals(sortby)) { Collections.sort(rooms, new RoomShortNameComparator()); } else { Collections.sort(rooms, new RoomServiceImpl.RoomNameComparator()); } return rooms.stream().map(toV2Migrator::migrate).collect(Collectors.toList()); } /** * Returns a list of my own Rooms with only the necessary information like name, keyword, or counters. */ @ApiOperation(value = "Retrieves a Room", nickname = "getMyRooms") @ApiResponses(value = { @ApiResponse(code = 204, message = HTML_STATUS_204) }) @RequestMapping(value = "/", method = RequestMethod.GET, params = "statusonly=true") @Pagination public List<Room> getMyRooms( @ApiParam(value = "visitedOnly", required = true) @RequestParam(value = "visitedonly", defaultValue = "false") final boolean visitedOnly, @ApiParam(value = "sort by", required = false) @RequestParam(value = "sortby", defaultValue = "name") final String sortby, final HttpServletResponse response ) { List<de.thm.arsnova.entities.Room> rooms; if (!visitedOnly) { rooms = roomService.getMyRoomsInfo(offset, limit); } else { rooms = roomService.getMyRoomHistoryInfo(offset, limit); } if (rooms == null || rooms.isEmpty()) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return null; } if ("shortname".equals(sortby)) { Collections.sort(rooms, new RoomShortNameComparator()); } else { Collections.sort(rooms, new RoomNameComparator()); } return rooms.stream().map(toV2Migrator::migrate).collect(Collectors.toList()); } @ApiOperation(value = "Retrieves all public pool Rooms for the current user", nickname = "getMyPublicPoolRooms") @ApiResponses(value = { @ApiResponse(code = 204, message = HTML_STATUS_204) }) @RequestMapping(value = "/publicpool", method = RequestMethod.GET, params = "statusonly=true") public List<Room> getMyPublicPoolRooms( final HttpServletResponse response ) { List<de.thm.arsnova.entities.Room> rooms = roomService.getMyPublicPoolRoomsInfo(); if (rooms == null || rooms.isEmpty()) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return null; } return rooms.stream().map(toV2Migrator::migrate).collect(Collectors.toList()); } @ApiOperation(value = "Retrieves all public pool Rooms", nickname = "getMyPublicPoolRooms") @ApiResponses(value = { @ApiResponse(code = 204, message = HTML_STATUS_204) }) @RequestMapping(value = "/publicpool", method = RequestMethod.GET) public List<Room> getPublicPoolRooms( final HttpServletResponse response ) { List<de.thm.arsnova.entities.Room> rooms = roomService.getPublicPoolRoomsInfo(); if (rooms == null || rooms.isEmpty()) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return null; } return rooms.stream().map(toV2Migrator::migrate).collect(Collectors.toList()); } @ApiOperation(value = "imports a Room", nickname = "importRoom") @RequestMapping(value = "/import", method = RequestMethod.POST) public Room importRoom( @ApiParam(value = "current Room", required = true) @RequestBody final ImportExportContainer room, final HttpServletResponse response ) { return toV2Migrator.migrate(roomService.importRooms(room)); } @ApiOperation(value = "export Rooms", nickname = "exportRoom") @RequestMapping(value = "/export", method = RequestMethod.GET) public List<ImportExportContainer> getExport( @ApiParam(value = "Room-Key", required = true) @RequestParam(value = "sessionkey", defaultValue = "") final List<String> shortIds, @ApiParam(value = "wether statistics shall be exported", required = true) @RequestParam(value = "withAnswerStatistics", defaultValue = "false") final Boolean withAnswerStatistics, @ApiParam(value = "wether comments shall be exported", required = true) @RequestParam(value = "withFeedbackQuestions", defaultValue = "false") final Boolean withFeedbackQuestions, final HttpServletResponse response ) { List<ImportExportContainer> rooms = new ArrayList<>(); ImportExportContainer temp; for (String shortId : shortIds) { roomService.setActive(shortId, false); temp = roomService.exportRoom(shortId, withAnswerStatistics, withFeedbackQuestions); if (temp != null) { rooms.add(temp); } roomService.setActive(shortId, true); } return rooms; } @ApiOperation(value = "copy a Rooms to the public pool if enabled") @RequestMapping(value = "/{shortId}/copytopublicpool", method = RequestMethod.POST) public Room copyToPublicPool( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "public pool attributes for Room", required = true) @RequestBody final ImportExportContainer.PublicPool publicPool ) { roomService.setActive(shortId, false); de.thm.arsnova.entities.Room roomInfo = roomService.copyRoomToPublicPool(shortId, publicPool); roomService.setActive(shortId, true); return toV2Migrator.migrate(roomInfo); } @ApiOperation(value = "Locks or unlocks a Room", nickname = "lockRoom") @ApiResponses(value = { @ApiResponse(code = 404, message = HTML_STATUS_404) }) @RequestMapping(value = "/{shortId}/lock", method = RequestMethod.POST) public Room lockRoom( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "lock", required = true) @RequestParam(required = false) final Boolean lock, final HttpServletResponse response ) { if (lock != null) { return toV2Migrator.migrate(roomService.setActive(shortId, lock)); } response.setStatus(HttpStatus.NOT_FOUND.value()); return null; } @ApiOperation(value = "retrieves a value for the score", nickname = "getLearningProgress") @RequestMapping(value = "/{shortId}/learningprogress", method = RequestMethod.GET) public ScoreStatistics getLearningProgress( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "type", required = false) @RequestParam(value = "type", defaultValue = "questions") final String type, @ApiParam(value = "question variant", required = false) @RequestParam(value = "questionVariant", required = false) final String questionVariant, final HttpServletResponse response ) { return roomService.getLearningProgress(shortId, type, questionVariant); } @ApiOperation(value = "retrieves a value for the learning progress for the current user", nickname = "getMyLearningProgress") @RequestMapping(value = "/{shortId}/mylearningprogress", method = RequestMethod.GET) public ScoreStatistics getMyLearningProgress( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @RequestParam(value = "type", defaultValue = "questions") final String type, @RequestParam(value = "questionVariant", required = false) final String questionVariant, final HttpServletResponse response ) { return roomService.getMyLearningProgress(shortId, type, questionVariant); } @ApiOperation(value = "retrieves all Room features", nickname = "getRoomFeatures") @RequestMapping(value = "/{shortId}/features", method = RequestMethod.GET) public RoomFeature getRoomFeatures( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, final HttpServletResponse response ) { de.thm.arsnova.entities.Room room = roomService.getByShortId(shortId); return toV2Migrator.migrate(room.getSettings()); } @RequestMapping(value = "/{shortId}/features", method = RequestMethod.PUT) @ApiOperation(value = "change all Room features", nickname = "changeRoomFeatures") public RoomFeature changeRoomFeatures( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "Room feature", required = true) @RequestBody final RoomFeature features, final HttpServletResponse response ) { de.thm.arsnova.entities.Room room = roomService.getByShortId(shortId); room.setSettings(fromV2Migrator.migrate(features)); roomService.update(shortId, room); return toV2Migrator.migrate(room.getSettings()); } @RequestMapping(value = "/{shortId}/lockfeedbackinput", method = RequestMethod.POST) @ApiOperation(value = "locks input of user live feedback", nickname = "lockFeedbackInput") public boolean lockFeedbackInput( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "lock", required = true) @RequestParam(required = true) final Boolean lock, final HttpServletResponse response ) { return roomService.lockFeedbackInput(shortId, lock); } @RequestMapping(value = "/{shortId}/flipflashcards", method = RequestMethod.POST) @ApiOperation(value = "flip all flashcards in Room", nickname = "lockFeedbackInput") public boolean flipFlashcards( @ApiParam(value = "Room-Key from current Room", required = true) @PathVariable final String shortId, @ApiParam(value = "flip", required = true) @RequestParam(required = true) final Boolean flip, final HttpServletResponse response ) { return roomService.flipFlashcards(shortId, flip); } /* internal redirections */ @RequestMapping(value = "/{shortId}/lecturerquestion") public String redirectLecturerQuestion( @PathVariable final String shortId, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/lecturerquestion/?sessionkey=%s", shortId); } @RequestMapping(value = "/{shortId}/lecturerquestion/{arg1}") public String redirectLecturerQuestionWithOneArgument( @PathVariable final String shortId, @PathVariable final String arg1, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/lecturerquestion/%s/?sessionkey=%s", arg1, shortId); } @RequestMapping(value = "/{shortId}/lecturerquestion/{arg1}/{arg2}") public String redirectLecturerQuestionWithTwoArguments( @PathVariable final String shortId, @PathVariable final String arg1, @PathVariable final String arg2, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/lecturerquestion/%s/%s/?sessionkey=%s", arg1, arg2, shortId); } @RequestMapping(value = "/{shortId}/lecturerquestion/{arg1}/{arg2}/{arg3}") public String redirectLecturerQuestionWithThreeArguments( @PathVariable final String shortId, @PathVariable final String arg1, @PathVariable final String arg2, @PathVariable final String arg3, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/lecturerquestion/%s/%s/%s/?sessionkey=%s", arg1, arg2, arg3, shortId); } @RequestMapping(value = "/{shortId}/audiencequestion") public String redirectAudienceQuestion( @PathVariable final String shortId, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/audiencequestion/?sessionkey=%s", shortId); } @RequestMapping(value = "/{shortId}/audiencequestion/{arg1}") public String redirectAudienceQuestionWithOneArgument( @PathVariable final String shortId, @PathVariable final String arg1, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/audiencequestion/%s/?sessionkey=%s", arg1, shortId); } @RequestMapping(value = "/{shortId}/audiencequestion/{arg1}/{arg2}") public String redirectAudienceQuestionWithTwoArguments( @PathVariable final String shortId, @PathVariable final String arg1, @PathVariable final String arg2, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/audiencequestion/%s/%s/?sessionkey=%s", arg1, arg2, shortId); } @RequestMapping(value = "/{shortId}/audiencequestion/{arg1}/{arg2}/{arg3}") public String redirectAudienceQuestionWithThreeArguments( @PathVariable final String shortId, @PathVariable final String arg1, @PathVariable final String arg2, @PathVariable final String arg3, final HttpServletResponse response ) { response.addHeader(X_FORWARDED, "1"); return String.format("forward:/audiencequestion/%s/%s/%s/?sessionkey=%s", arg1, arg2, arg3, shortId); } }