diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java index 1ee9bcdd3b552d7315038b788735b61afde96461..f846b836409cd9038fa4b5453050f089f53d6cf8 100644 --- a/src/main/java/de/thm/arsnova/controller/SessionController.java +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -77,8 +77,15 @@ public class SessionController extends PaginationController { @DeprecatedApi @Deprecated @RequestMapping(value = "/{sessionkey}", method = RequestMethod.GET) - public Session joinSession(@ApiParam(value = "Session-Key from current session", required = true) @PathVariable final String sessionkey) { - return Session.anonymizedCopy(sessionService.getSession(sessionkey)); + public Session joinSession( + @ApiParam(value = "Session-Key from current session", required = true) @PathVariable final String sessionkey, + @ApiParam(value = "Adminflag", required = false) @RequestParam(value = "admin", defaultValue = "false") final boolean admin + ) { + if (admin) { + return sessionService.getSessionForAdmin(sessionkey); + } else { + return sessionService.getSession(sessionkey); + } } @ApiOperation(value = "deletes a session", @@ -139,6 +146,15 @@ public class SessionController extends PaginationController { return sessionService.updateSession(sessionkey, session); } + @ApiOperation(value = "change the session creator (owner)", nickname = "changeSessionCreator") + @RequestMapping(value = "/{sessionkey}/changecreator", method = RequestMethod.PUT) + public Session changeSessionCreator( + @ApiParam(value = "session-key from current session", required = true) @PathVariable final String sessionkey, + @ApiParam(value = "new session creator", required = true) @RequestBody final String newCreator + ) { + return sessionService.changeSessionCreator(sessionkey, newCreator); + } + @ApiOperation(value = "Retrieves a list of Sessions", nickname = "getSessions") @ApiResponses(value = { @@ -151,22 +167,39 @@ public class SessionController extends PaginationController { @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<Session> sessions = null; - /* TODO implement all parameter combinations, implement use of user parameter */ - try { - if (ownedOnly && !visitedOnly) { - sessions = sessionService.getMySessions(offset, limit); - } else if (visitedOnly && !ownedOnly) { - sessions = sessionService.getMyVisitedSessions(offset, limit); - } else { - response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); - return null; + if (!username.equals("")) { + try { + if (ownedOnly && !visitedOnly) { + sessions = sessionService.getUserSessions(username); + } else if (visitedOnly && !ownedOnly) { + sessions = sessionService.getUserVisitedSessions(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) { + sessions = sessionService.getMySessions(offset, limit); + } else if (visitedOnly && !ownedOnly) { + sessions = sessionService.getMyVisitedSessions(offset, limit); + } else { + response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); + return null; + } + } catch (final AccessDeniedException e) { + throw new UnauthorizedException(); } - } catch (final AccessDeniedException e) { - throw new UnauthorizedException(); } if (sessions == null || sessions.isEmpty()) { diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index 5f2781d8e668e9cf9e82f5a484b7eeb99e06c2b5..3ada67b9da35912324969fcdb75e2b0be232e319 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -153,6 +153,11 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Override public List<Session> getMySessions(final User user, final int start, final int limit) { + return this.getDatabaseDao().getSessionsForUsername(user.getUsername(), start, limit); + } + + @Override + public List<Session> getSessionsForUsername(String username, final int start, final int limit) { final NovaView view = new NovaView("session/by_creator"); if (start > 0) { view.setSkip(start); @@ -160,8 +165,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware if (limit > 0) { view.setLimit(limit); } - view.setStartKeyArray(user.getUsername()); - view.setEndKeyArray(user.getUsername(), "{}"); + view.setStartKeyArray(username); + view.setEndKeyArray(username, "{}"); final Results<Session> results = getDatabase().queryView(view, Session.class); @@ -1398,6 +1403,72 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware return result; } + @Override + public List<Session> getVisitedSessionsForUsername(String username, final int start, final int limit) { + final NovaView view = new NovaView("logged_in/visited_sessions_by_user"); + if (start > 0) { + view.setSkip(start); + } + if (limit > 0) { + view.setLimit(limit); + } + view.setKey(username); + final ViewResults sessions = getDatabase().view(view); + final List<Session> allSessions = new ArrayList<Session>(); + for (final Document d : sessions.getResults()) { + // Not all users have visited sessions + if (d.getJSONObject().optJSONArray("value") != null) { + @SuppressWarnings("unchecked") + final Collection<Session> visitedSessions = JSONArray.toCollection( + d.getJSONObject().getJSONArray("value"), + Session.class + ); + allSessions.addAll(visitedSessions); + } + } + // Filter sessions that don't exist anymore, also filter my own sessions + final List<Session> result = new ArrayList<Session>(); + final List<Session> filteredSessions = new ArrayList<Session>(); + for (final Session s : allSessions) { + try { + final Session session = getDatabaseDao().getSessionFromKeyword(s.getKeyword()); + if (session != null && !(session.getCreator().equals(username))) { + result.add(session); + } else { + filteredSessions.add(s); + } + } catch (final NotFoundException e) { + filteredSessions.add(s); + } + } + if (filteredSessions.isEmpty()) { + return result; + } + // Update document to remove sessions that don't exist anymore + try { + List<VisitedSession> visitedSessions = new ArrayList<VisitedSession>(); + for (final Session s : result) { + visitedSessions.add(new VisitedSession(s)); + } + final LoggedIn loggedIn = new LoggedIn(); + final Document loggedInDocument = getDatabase().getDocument(sessions.getResults().get(0).getString("id")); + loggedIn.setSessionId(loggedInDocument.getString("sessionId")); + loggedIn.setUser(username); + loggedIn.setTimestamp(loggedInDocument.getLong("timestamp")); + loggedIn.setType(loggedInDocument.getString("type")); + loggedIn.setVisitedSessions(visitedSessions); + loggedIn.set_id(loggedInDocument.getId()); + loggedIn.set_rev(loggedInDocument.getRev()); + + final JSONObject json = JSONObject.fromObject(loggedIn); + final Document doc = new Document(json); + getDatabase().saveDocument(doc); + } catch (IOException e) { + LOGGER.error("Could not clean up logged_in document of {}", username); + } + return result; + } + @Override public List<SessionInfo> getMyVisitedSessionsInfo(final User user, final int start, final int limit) { List<Session> sessions = this.getMyVisitedSessions(user, start, limit); @@ -1586,6 +1657,21 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Override @Caching(evict = { @CacheEvict("sessions"), @CacheEvict(cacheNames = "sessions", key = "#p0.keyword") }) + public Session changeSessionCreator(Session session, final String newCreator) { + try { + final Document s = database.getDocument(session.get_id()); + s.put("creator", newCreator); + database.saveDocument(s); + session.set_rev(s.getRev()); + } catch (final IOException e) { + LOGGER.error("Could not lock session {}", session); + } + + return session; + } + + @Override + @Caching(evict = { @CacheEvict("sessions"), @CacheEvict(cacheNames="sessions", key="#p0.keyword") }) public void deleteSession(final Session session) { try { deleteDocument(session.get_id()); diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index b7a6331940d0b87f77c2c75611d16006a274cf9d..378d6ae62393fcea679eee68da4879f51c591ae1 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -44,6 +44,8 @@ public interface IDatabaseDao { List<Session> getMySessions(User user, final int start, final int limit); + List<Session> getSessionsForUsername(String username, final int start, final int limit); + List<Session> getPublicPoolSessions(); List<Session> getMyPublicPoolSessions(User user); @@ -121,6 +123,8 @@ public interface IDatabaseDao { List<Session> getMyVisitedSessions(User user, final int start, final int limit); + List<Session> getVisitedSessionsForUsername(String username, final int start, final int limit); + Question updateQuestion(Question question); void deleteAnswers(Question question); @@ -139,6 +143,8 @@ public interface IDatabaseDao { Session updateSession(Session session); + Session changeSessionCreator(Session session, String newCreator); + void deleteSession(Session session); List<Question> getLectureQuestionsForUsers(Session session); diff --git a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java index 1bd925c702e195ffecdddd0c6bd477c2c891e404..6239be2ca2927d16487bee3fdefbf85d7b6d0d49 100644 --- a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java +++ b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java @@ -58,8 +58,9 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final Object permission ) { final String username = getUsername(authentication); - - if ( + if (checkAdminPermission(username)) { + return true; + } else if ( targetDomainObject instanceof Session && checkSessionPermission(username, ((Session) targetDomainObject).getKeyword(), permission) ) { @@ -76,8 +77,9 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final Object permission ) { final String username = getUsername(authentication); - - if ( + if (checkAdminPermission(username)) { + return true; + } else if ( "session".equals(targetType) && checkSessionPermission(username, targetId, permission)) { return true; @@ -91,15 +93,15 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { && checkInterposedQuestionPermission(username, targetId, permission) ) { return true; - } else if ( - /*TODO only account from own database*/ - "motd".equals(targetType) - && permission.equals("admin") - ) { - String[] splittedNames = adminAccounts.split(","); - if (Arrays.asList(splittedNames).contains(username)) { - return true; - } + } + return false; + } + + private boolean checkAdminPermission(final String username) { + /** TODO only allow accounts from arsnova db **/ + String[] splittedAdminNames = adminAccounts.split(","); + if (Arrays.asList(splittedAdminNames).contains(username)) { + return true; } return false; } diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index 368305dd940658002d07a5c47d0022f11e3af421..10f06e390beced23c4ff7ac7ee3009cd25cba9e0 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -34,6 +34,8 @@ import java.util.UUID; public interface ISessionService { Session getSession(String keyword); + Session getSessionForAdmin(final String keyword); + Session getSessionInternal(String keyword, User user); Session saveSession(Session session); @@ -42,6 +44,10 @@ public interface ISessionService { String generateKeyword(); + List<Session> getUserSessions(String username); + + List<Session> getUserVisitedSessions(String username); + List<Session> getMySessions(int offset, int limit); List<Session> getMyVisitedSessions(int offset, int limit); @@ -56,6 +62,8 @@ public interface ISessionService { Session updateSession(String sessionkey, Session session); + Session changeSessionCreator(String sessionkey, String newCreator); + Session updateSessionInternal(Session session, User user); void deleteSession(String sessionkey); diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index dd3ea57316b2fdc042787b655b245de762d9b066..8894b82cc457c0178f2cd2506184f001adfd0cbf 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -160,7 +160,13 @@ public class SessionService implements ISessionService, ApplicationEventPublishe @PreAuthorize("isAuthenticated()") public Session getSession(final String keyword) { final User user = userService.getCurrentUser(); - return this.getSessionInternal(keyword, user); + return Session.anonymizedCopy(this.getSessionInternal(keyword, user)); + } + + @PreAuthorize("isAuthenticated() and hasPermission(#sessionkey, 'session', 'owner')") + public Session getSessionForAdmin(final String keyword) { + final Session session = databaseDao.getSessionFromKeyword(keyword); + return session; } /* @@ -189,6 +195,12 @@ public class SessionService implements ISessionService, ApplicationEventPublishe return session; } + @Override + @PreAuthorize("isAuthenticated() and hasPermission(#sessionkey, 'session', 'owner')") + public List<Session> getUserSessions(String username) { + return databaseDao.getSessionsForUsername(username, 0, 0); + } + @Override @PreAuthorize("isAuthenticated()") public List<Session> getMySessions(final int offset, final int limit) { @@ -220,6 +232,12 @@ public class SessionService implements ISessionService, ApplicationEventPublishe return databaseDao.getMyVisitedSessions(userService.getCurrentUser(), offset, limit); } + @Override + @PreAuthorize("isAuthenticated() and hasPermission(1, 'motd', 'admin')") + public List<Session> getUserVisitedSessions(String username) { + return databaseDao.getVisitedSessionsForUsername(username, 0, 0); + } + @Override @PreAuthorize("isAuthenticated()") public List<SessionInfo> getMyVisitedSessionsInfo(final int offset, final int limit) { @@ -327,6 +345,16 @@ public class SessionService implements ISessionService, ApplicationEventPublishe return databaseDao.updateSession(existingSession); } + @Override + @PreAuthorize("isAuthenticated() and hasPermission(1,'motd','admin')") + public Session changeSessionCreator(String sessionkey, String newCreator) { + final Session existingSession = databaseDao.getSessionFromKeyword(sessionkey); + if (existingSession == null) { + throw new RuntimeException("Error while trying to get the session with sessionkey: " + sessionkey); + } + return databaseDao.changeSessionCreator(existingSession, newCreator); + } + /* * The "internal" suffix means it is called by internal services that have no authentication! * TODO: Find a better way of doing this... diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index 65a72f179110a6ba3ef2ce6cefabb6185ff90acb..e3742e232dba58a2f6f61aacdbb562ae2ee3a412 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -163,6 +163,12 @@ public class StubDatabaseDao implements IDatabaseDao { return null; } + @Override + public List<Session> getSessionsForUsername(String username, final int start, final int limit) { + // TODO Auto-generated method stub + return null; + } + @Override public List<Session> getPublicPoolSessions() { // TODO Auto-generated method stub @@ -329,6 +335,12 @@ public class StubDatabaseDao implements IDatabaseDao { return null; } + @Override + public Session changeSessionCreator(Session session, final String newCreator) { + // TODO Auto-generated method stub + return null; + } + @Override public void deleteSession(Session session) { // TODO Auto-generated method stub @@ -477,6 +489,12 @@ public class StubDatabaseDao implements IDatabaseDao { return null; } + @Override + public List<Session> getVisitedSessionsForUsername(String username, final int start, final int limit) { + // TODO Auto-generated method stub + return null; + } + @Override public void deleteAllPreparationAnswers(Session session) { // TODO Auto-generated method stub