diff --git a/src/main/java/de/thm/arsnova/controller/FeedbackController.java b/src/main/java/de/thm/arsnova/controller/FeedbackController.java new file mode 100644 index 0000000000000000000000000000000000000000..9e3a7a340831c2a3d05a84b4e66220f71f22affa --- /dev/null +++ b/src/main/java/de/thm/arsnova/controller/FeedbackController.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 THM webMedia + * + * This file is part of ARSnova. + * + * ARSnova 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 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; + +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +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.ResponseBody; + +import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.User; +import de.thm.arsnova.services.ISessionService; +import de.thm.arsnova.services.IUserService; +import de.thm.arsnova.socket.ARSnovaSocketIOServer; + +@Controller +public class FeedbackController extends AbstractController { + + public static final Logger logger = LoggerFactory.getLogger(FeedbackController.class); + + @Autowired + ISessionService sessionService; + + @Autowired + IUserService userService; + + @Autowired + ARSnovaSocketIOServer server; + + @RequestMapping(value="/session/{sessionkey}/feedback", method=RequestMethod.GET) + @ResponseBody + public Feedback getFeedback(@PathVariable String sessionkey) { + return sessionService.getFeedback(sessionkey); + } + + @RequestMapping(value="/session/{sessionkey}/feedback", method=RequestMethod.POST) + @ResponseBody + public Feedback postFeedback(@PathVariable String sessionkey, @RequestBody int value, HttpServletResponse response) { + User user = userService.getUser(SecurityContextHolder.getContext().getAuthentication()); + if (sessionService.saveFeedback(sessionkey, value, user)) { + Feedback feedback = sessionService.getFeedback(sessionkey); + if (feedback != null) { + // TODO: Broadcast feedback changes via websocket + response.setStatus(HttpStatus.CREATED.value()); + return feedback; + } + + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + return null; + } + + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return null; + } +} diff --git a/src/main/java/de/thm/arsnova/controller/QuestionController.java b/src/main/java/de/thm/arsnova/controller/QuestionController.java new file mode 100644 index 0000000000000000000000000000000000000000..184d7e88d46d518f8a62fa1aef62bfe356247bf7 --- /dev/null +++ b/src/main/java/de/thm/arsnova/controller/QuestionController.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 THM webMedia + * + * This file is part of ARSnova. + * + * ARSnova 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 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; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +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.ResponseBody; + +import de.thm.arsnova.entities.Question; + +import de.thm.arsnova.services.ISessionService; +import de.thm.arsnova.services.IUserService; +import de.thm.arsnova.socket.ARSnovaSocketIOServer; + + +@Controller +public class QuestionController extends AbstractController { + + public static final Logger logger = LoggerFactory.getLogger(QuestionController.class); + + @Autowired + ISessionService sessionService; + + @Autowired + IUserService userService; + + @Autowired + ARSnovaSocketIOServer server; + + @RequestMapping(value="/session/{sessionkey}/question/{questionId}", method=RequestMethod.GET) + @ResponseBody + public Question getQuestion(@PathVariable String sessionkey, @PathVariable String questionId, HttpServletResponse response) { + Question question = sessionService.getQuestion(questionId); + if (question != null && question.getSession().equals(sessionkey)) { + return question; + } + + response.setStatus(HttpStatus.NOT_FOUND.value()); + return null; + } + + @RequestMapping(value="/session/{sessionkey}/question", method=RequestMethod.POST) + @ResponseBody + public void postQuestion(@PathVariable String sessionkey, @RequestBody Question question, HttpServletResponse response) { + if (! sessionkey.equals(question.getSession())) { + response.setStatus(HttpStatus.PRECONDITION_FAILED.value()); + return; + } + + if (sessionService.saveQuestion(question)) { + response.setStatus(HttpStatus.CREATED.value()); + return; + } + + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return; + } + + @RequestMapping( + value={ + "/getSkillQuestions/{sessionkey}", + "/session/{sessionkey}/skillquestions" + }, + method=RequestMethod.GET + ) + @ResponseBody + public List<Question> getSkillQuestions(@PathVariable String sessionkey, @RequestParam(value="sort", required=false) String sort, HttpServletResponse response) { + List<Question> questions = sessionService.getSkillQuestions(sessionkey, sort); + if(questions == null || questions.isEmpty()) { + response.setStatus(HttpStatus.NOT_FOUND.value()); + return null; + } + logger.info(questions.toString()); + return questions; + } +} diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java index 007b5dd000ac880bad939f6f8cac5061ec1d7335..906fe66041bee8c6094dd82a0edfecca1a36cbb5 100644 --- a/src/main/java/de/thm/arsnova/controller/SessionController.java +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -172,7 +172,7 @@ public class SessionController extends AbstractController { return url.toString(); } - @RequestMapping(value="/mySessions", method=RequestMethod.GET) + @RequestMapping(value={"/mySessions","/session/mysessions"}, method=RequestMethod.GET) @ResponseBody public List<Session> getMySession(HttpServletResponse response) { String username = userService.getUser(SecurityContextHolder.getContext().getAuthentication()).getUsername(); diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index 435554e2658327252be550c79689f130d2f21b42..9609b2ed73016f7d0a4bab9d09bf26636848b4f8 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -34,11 +34,15 @@ import java.util.Set; import net.sf.ezmorph.Morpher; import net.sf.ezmorph.MorpherRegistry; import net.sf.ezmorph.bean.BeanMorpher; +import net.sf.ezmorph.bean.MorphDynaBean; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONObject; +import net.sf.json.JsonConfig; import net.sf.json.util.JSONUtils; +import org.apache.commons.beanutils.DynaBean; +import org.apache.commons.beanutils.DynaClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -55,6 +59,8 @@ import com.fourspaces.couchdb.View; import com.fourspaces.couchdb.ViewResults; import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.PossibleAnswer; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.LoggedIn; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; @@ -515,45 +521,4 @@ public class CouchDBDao implements IDatabaseDao { } return null; } - - @Override - public LoggedIn registerAsOnlineUser(User u, Session s) { - try { - View view = new View("logged_in/all"); - view.setKey(URLEncoder.encode("\"" + u.getUsername() + "\"", "UTF-8")); - ViewResults results = this.getDatabase().view(view); - - LoggedIn loggedIn = new LoggedIn(); - if (results.getJSONArray("rows").optJSONObject(0) != null) { - JSONObject json = results.getJSONArray("rows").optJSONObject(0).optJSONObject("value"); - loggedIn = (LoggedIn) JSONObject.toBean(json, LoggedIn.class); - Collection<VisitedSession> visitedSessions = JSONArray.toCollection(json.getJSONArray("visitedSessions"), VisitedSession.class); - loggedIn.setVisitedSessions(new ArrayList<VisitedSession>(visitedSessions)); - } - - loggedIn.setUser(u.getUsername()); - loggedIn.setSessionId(s.get_id()); - loggedIn.addVisitedSession(s); - - JSONObject json = JSONObject.fromObject(loggedIn); - Document doc = new Document(json); - if (doc.getId() == "") { - // If this is a new user without a logged_in document, we have to remove the following - // pre-filled fields. Otherwise, CouchDB will take these empty fields as genuine - // identifiers, and will throw errors afterwards. - doc.remove("_id"); - doc.remove("_rev"); - } - this.getDatabase().saveDocument(doc); - - LoggedIn l = (LoggedIn) JSONObject.toBean(doc.getJSONObject(), LoggedIn.class); - Collection<VisitedSession> visitedSessions = JSONArray.toCollection(doc.getJSONObject().getJSONArray("visitedSessions"), VisitedSession.class); - l.setVisitedSessions(new ArrayList<VisitedSession>(visitedSessions)); - return l; - } catch (UnsupportedEncodingException e) { - return null; - } catch (IOException e) { - return null; - } - } } diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index e1d2545c3720b09ee10c2a4c5adb66202289711a..97d4988d0ce732206c36264f07ff5979dfda9a49 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -22,10 +22,10 @@ package de.thm.arsnova.dao; import java.util.List; import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.LoggedIn; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; -import de.thm.arsnova.socket.message.Question; public interface IDatabaseDao { public void cleanFeedbackVotes(int cleanupFeedbackDelay); diff --git a/src/main/java/de/thm/arsnova/socket/message/Authorize.java b/src/main/java/de/thm/arsnova/entities/Authorize.java similarity index 91% rename from src/main/java/de/thm/arsnova/socket/message/Authorize.java rename to src/main/java/de/thm/arsnova/entities/Authorize.java index 7b0c4eeb8929c086dbced9a2ceeec42317624573..170c7cd95af9bb9565d5b43c92fe71b7557bc7ef 100644 --- a/src/main/java/de/thm/arsnova/socket/message/Authorize.java +++ b/src/main/java/de/thm/arsnova/entities/Authorize.java @@ -1,4 +1,4 @@ -package de.thm.arsnova.socket.message; +package de.thm.arsnova.entities; public class Authorize { private String user; diff --git a/src/main/java/de/thm/arsnova/socket/message/PossibleAnswer.java b/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java similarity index 96% rename from src/main/java/de/thm/arsnova/socket/message/PossibleAnswer.java rename to src/main/java/de/thm/arsnova/entities/PossibleAnswer.java index c25f64025f3459819a0193e8d6f56f7b3d278f0a..e02dc30ab3b0610e2e9b71f1129525f5e17051f4 100644 --- a/src/main/java/de/thm/arsnova/socket/message/PossibleAnswer.java +++ b/src/main/java/de/thm/arsnova/entities/PossibleAnswer.java @@ -16,7 +16,7 @@ * 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.socket.message; +package de.thm.arsnova.entities; public class PossibleAnswer { diff --git a/src/main/java/de/thm/arsnova/socket/message/Question.java b/src/main/java/de/thm/arsnova/entities/Question.java similarity index 98% rename from src/main/java/de/thm/arsnova/socket/message/Question.java rename to src/main/java/de/thm/arsnova/entities/Question.java index a5b10ee50296da44e63261ae8d78477453732af4..b72a37873bc40ebde891e35123aaea4b673ff748 100644 --- a/src/main/java/de/thm/arsnova/socket/message/Question.java +++ b/src/main/java/de/thm/arsnova/entities/Question.java @@ -16,7 +16,7 @@ * 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.socket.message; +package de.thm.arsnova.entities; import java.util.List; diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index 42b3200615dbec69c9871db9e60e3c0a3027963c..392c0f36948d07982caf6ad87745fe374650a436 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -24,12 +24,11 @@ import java.util.Map; import java.util.Set; import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.LoggedIn; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; -import de.thm.arsnova.socket.message.Question; - public interface ISessionService { @@ -50,5 +49,4 @@ public interface ISessionService { public Question getQuestion(String id); public List<Question> getSkillQuestions(String sessionkey, String sort); public int getSkillQuestionCount(String sessionkey); - public LoggedIn registerAsOnlineUser(User user, String sessionkey); } \ No newline at end of file diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index e076aa898f2d3e169f2be72368a5a197cb1014f5..739af73959e6aa041ff51410a4811350b101d1ef 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -36,11 +36,11 @@ import org.springframework.transaction.annotation.Transactional; import de.thm.arsnova.annotation.Authenticated; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.LoggedIn; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; import de.thm.arsnova.socket.ARSnovaSocketIOServer; -import de.thm.arsnova.socket.message.Question; @Service public class SessionService implements ISessionService { diff --git a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java index 4ce5698c03ba9f8f010af3e09b7f5b6c7064c582..8298289f93be85448116a3177d30805539ddf37b 100644 --- a/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java +++ b/src/main/java/de/thm/arsnova/socket/ARSnovaSocketIOServer.java @@ -23,10 +23,10 @@ import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.DataListener; import com.corundumstudio.socketio.listener.DisconnectListener; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.User; import de.thm.arsnova.services.ISessionService; import de.thm.arsnova.socket.message.Feedback; -import de.thm.arsnova.socket.message.Question; public class ARSnovaSocketIOServer { diff --git a/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java b/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..17e3b11a28435b37156af70e6c9f8514167f9d99 --- /dev/null +++ b/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java @@ -0,0 +1,89 @@ +package de.thm.arsnova.controller; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import javax.inject.Inject; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.servlet.HandlerAdapter; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; + +import de.thm.arsnova.exceptions.NotFoundException; +import de.thm.arsnova.exceptions.UnauthorizedException; +import de.thm.arsnova.services.StubUserService; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "file:src/main/webapp/WEB-INF/arsnova-servlet.xml", + "file:src/main/webapp/WEB-INF/spring/spring-main.xml", + "file:src/test/resources/test-config.xml" }) +public class FeedbackControllerTest { + + @Inject + private ApplicationContext applicationContext; + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private HandlerAdapter handlerAdapter; + + @Autowired + private FeedbackController feedbackController; + + @Autowired + private StubUserService userService; + + @Before + public void setUp() { + this.request = new MockHttpServletRequest(); + this.response = new MockHttpServletResponse(); + handlerAdapter = applicationContext + .getBean(AnnotationMethodHandlerAdapter.class); + } + + @Test(expected=NotFoundException.class) + public void testShouldNotGetFeedbackForUnknownSession() throws Exception { + userService.setUserAuthenticated(true); + + request.setMethod("GET"); + request.setRequestURI("/session/00000000/feedback"); + final ModelAndView mav = handlerAdapter.handle(request, response, feedbackController); + + assertNull(mav); + assertTrue(response.getStatus() == 404); + } + + @Test(expected=UnauthorizedException.class) + public void testShouldNotGetFeedbackIfUnauthorized() throws Exception { + userService.setUserAuthenticated(false); + + request.setMethod("GET"); + request.setRequestURI("/session/00000000/feedback"); + final ModelAndView mav = handlerAdapter.handle(request, response, feedbackController); + + assertNull(mav); + assertTrue(response.getStatus() == 401); + } + + @Test(expected=UnauthorizedException.class) + public void testShouldNotSaveFeedbackIfUnauthorized() throws Exception { + userService.setUserAuthenticated(false); + + request.setMethod("POST"); + request.setRequestURI("/session/00000000/feedback"); + request.setContentType("application/json"); + request.setContent("0".getBytes()); + final ModelAndView mav = handlerAdapter.handle(request, response, feedbackController); + + assertNull(mav); + assertTrue(response.getStatus() == 401); + } +} diff --git a/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java b/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java index df4c2530ef8fb7666d2438b91cb9ce72461ac4d9..56418baf032ce1131a97e3e1def117cae3763050 100644 --- a/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/SessionControllerTest.java @@ -100,42 +100,4 @@ public class SessionControllerTest { assertNull(mav); assertTrue(response.getStatus() == 401); } - - @Test(expected=NotFoundException.class) - public void testShouldNotGetFeedbackForUnknownSession() throws Exception { - userService.setUserAuthenticated(true); - - request.setMethod("GET"); - request.setRequestURI("/session/00000000/feedback"); - final ModelAndView mav = handlerAdapter.handle(request, response, sessionController); - - assertNull(mav); - assertTrue(response.getStatus() == 404); - } - - @Test(expected=UnauthorizedException.class) - public void testShouldNotGetFeedbackIfUnauthorized() throws Exception { - userService.setUserAuthenticated(false); - - request.setMethod("GET"); - request.setRequestURI("/session/00000000/feedback"); - final ModelAndView mav = handlerAdapter.handle(request, response, sessionController); - - assertNull(mav); - assertTrue(response.getStatus() == 401); - } - - @Test(expected=UnauthorizedException.class) - public void testShouldNotSaveFeedbackIfUnauthorized() throws Exception { - userService.setUserAuthenticated(false); - - request.setMethod("POST"); - request.setRequestURI("/session/00000000/feedback"); - request.setContentType("application/json"); - request.setContent("0".getBytes()); - final ModelAndView mav = handlerAdapter.handle(request, response, sessionController); - - assertNull(mav); - assertTrue(response.getStatus() == 401); - } } diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index b5b94afe8b2b056f9d3f43f31b88652e3c26703f..3594c5dd9efc4d2b8a9580bb393e974cc2a221bd 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -10,12 +10,12 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.Question; import de.thm.arsnova.entities.LoggedIn; import de.thm.arsnova.entities.Session; import de.thm.arsnova.entities.User; import de.thm.arsnova.exceptions.ForbiddenException; import de.thm.arsnova.exceptions.NotFoundException; -import de.thm.arsnova.socket.message.Question; @Component @Scope("singleton")