diff --git a/src/main/java/de/thm/arsnova/config/AppConfig.java b/src/main/java/de/thm/arsnova/config/AppConfig.java index 1e992cb6dfbec9909b35417a56a4646f5b2ad3e6..5be42080de92e3dece36b1bb8ac671b7da660edb 100644 --- a/src/main/java/de/thm/arsnova/config/AppConfig.java +++ b/src/main/java/de/thm/arsnova/config/AppConfig.java @@ -22,9 +22,10 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import io.micrometer.core.instrument.MeterRegistry; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang.CharEncoding; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; @@ -116,7 +117,7 @@ import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl; "classpath:config/actuator.yml", "file:${arsnova.config-dir:.}/application.yml"}, ignoreResourceNotFound = true, - encoding = "UTF-8", + encoding = CharEncoding.UTF_8, factory = YamlPropertySourceFactory.class ) @EnableConfigurationProperties(SystemProperties.class) @@ -209,7 +210,7 @@ public class AppConfig implements WebMvcConfigurer { @Bean public StringHttpMessageConverter stringMessageConverter() { final StringHttpMessageConverter messageConverter = new StringHttpMessageConverter(); - messageConverter.setDefaultCharset(Charset.forName("UTF-8")); + messageConverter.setDefaultCharset(StandardCharsets.UTF_8); messageConverter.setWriteAcceptCharset(false); final List<MediaType> mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.TEXT_PLAIN); diff --git a/src/main/java/de/thm/arsnova/config/SecurityConfig.java b/src/main/java/de/thm/arsnova/config/SecurityConfig.java index cb327b08e0ae5208230a5d6d3c7c4f530f144100..d35604377a0d1f412cf372a32b099c5efa3606c1 100644 --- a/src/main/java/de/thm/arsnova/config/SecurityConfig.java +++ b/src/main/java/de/thm/arsnova/config/SecurityConfig.java @@ -116,6 +116,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { public static final String CAS_LOGIN_PATH_SUFFIX = "/auth/login/cas"; public static final String CAS_LOGOUT_PATH_SUFFIX = "/auth/logout/cas"; public static final String RUN_AS_KEY_PREFIX = "RUN_AS_KEY"; + public static final String INTERNAL_PROVIDER_ID = "user-db"; + public static final String LDAP_PROVIDER_ID = "ldap"; + public static final String OIDC_PROVIDER_ID = "oidc"; + public static final String CAS_PROVIDER_ID = "cas"; + public static final String GOOGLE_PROVIDER_ID = "google"; + public static final String TWITTER_PROVIDER_ID = "twitter"; + public static final String FACEBOOK_PROVIDER_ID = "facebook"; private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class); private ServletContext servletContext; @@ -250,32 +257,32 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { auth.authenticationProvider(jwtAuthenticationProvider()); logger.info("oauthProps: {}", providerProperties.getOauth()); if (providerProperties.getLdap().stream().anyMatch(p -> p.isEnabled())) { - providers.add("ldap"); + providers.add(LDAP_PROVIDER_ID); auth.authenticationProvider(ldapAuthenticationProvider()); } if (providerProperties.getCas().isEnabled()) { - providers.add("cas"); + providers.add(CAS_PROVIDER_ID); auth.authenticationProvider(casAuthenticationProvider()); } if (providerProperties.getRegistered().isEnabled()) { - providers.add("user-db"); + providers.add(INTERNAL_PROVIDER_ID); auth.authenticationProvider(daoAuthenticationProvider()); } if (providerProperties.getOidc().stream().anyMatch(p -> p.isEnabled())) { - providers.add("oidc"); + providers.add(OIDC_PROVIDER_ID); } if (providerProperties.getOauth().values().stream().anyMatch(p -> p.isEnabled())) { - if (providerProperties.getOauth().containsKey("google") - && providerProperties.getOauth().get("google").isEnabled()) { - providers.add("google"); + if (providerProperties.getOauth().containsKey(GOOGLE_PROVIDER_ID) + && providerProperties.getOauth().get(GOOGLE_PROVIDER_ID).isEnabled()) { + providers.add(GOOGLE_PROVIDER_ID); } - if (providerProperties.getOauth().containsKey("facebook") - && providerProperties.getOauth().get("facebook").isEnabled()) { - providers.add("facebook"); + if (providerProperties.getOauth().containsKey(FACEBOOK_PROVIDER_ID) + && providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID).isEnabled()) { + providers.add(FACEBOOK_PROVIDER_ID); } - if (providerProperties.getOauth().containsKey("twitter") - && providerProperties.getOauth().get("twitter").isEnabled()) { - providers.add("twitter"); + if (providerProperties.getOauth().containsKey(TWITTER_PROVIDER_ID) + && providerProperties.getOauth().get(TWITTER_PROVIDER_ID).isEnabled()) { + providers.add(TWITTER_PROVIDER_ID); } auth.authenticationProvider(oauthAuthenticationProvider()); } @@ -513,16 +520,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { if (providerProperties.getOidc().stream().anyMatch(p -> p.isEnabled())) { clients.add(oidcClient()); } - if (providerProperties.getOauth().containsKey("facebook") - && providerProperties.getOauth().get("facebook").isEnabled()) { + if (providerProperties.getOauth().containsKey(FACEBOOK_PROVIDER_ID) + && providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID).isEnabled()) { clients.add(facebookClient()); } - if (providerProperties.getOauth().containsKey("google") - && providerProperties.getOauth().get("google").isEnabled()) { + if (providerProperties.getOauth().containsKey(GOOGLE_PROVIDER_ID) + && providerProperties.getOauth().get(GOOGLE_PROVIDER_ID).isEnabled()) { clients.add(googleClient()); } - if (providerProperties.getOauth().containsKey("twitter") - && providerProperties.getOauth().get("twitter").isEnabled()) { + if (providerProperties.getOauth().containsKey(TWITTER_PROVIDER_ID) + && providerProperties.getOauth().get(TWITTER_PROVIDER_ID).isEnabled()) { clients.add(twitterClient()); } @@ -559,7 +566,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public FacebookClient facebookClient() { - final AuthenticationProviderProperties.Oauth oauthProperties = providerProperties.getOauth().get("facebook"); + final AuthenticationProviderProperties.Oauth oauthProperties = + providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID); final FacebookClient client = new FacebookClient(oauthProperties.getKey(), oauthProperties.getSecret()); client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH_SUFFIX + "?client_name=FacebookClient"); @@ -568,7 +576,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public TwitterClient twitterClient() { - final AuthenticationProviderProperties.Oauth oauthProperties = providerProperties.getOauth().get("twitter"); + final AuthenticationProviderProperties.Oauth oauthProperties = + providerProperties.getOauth().get(TWITTER_PROVIDER_ID); final TwitterClient client = new TwitterClient(oauthProperties.getKey(), oauthProperties.getSecret()); client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH_SUFFIX + "?client_name=TwitterClient"); @@ -577,7 +586,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public GoogleOidcClient googleClient() { - final AuthenticationProviderProperties.Oauth oauthProperties = providerProperties.getOauth().get("google"); + final AuthenticationProviderProperties.Oauth oauthProperties = + providerProperties.getOauth().get(GOOGLE_PROVIDER_ID); final OidcConfiguration config = new OidcConfiguration(); config.setClientId(oauthProperties.getKey()); config.setSecret(oauthProperties.getSecret()); diff --git a/src/main/java/de/thm/arsnova/controller/v2/AuthenticationController.java b/src/main/java/de/thm/arsnova/controller/v2/AuthenticationController.java index c6065c0e25195ff1a50f6842b7e5a0e6225c39a1..fd52193a804f77260d518bfec4cf578e7d5ca130 100644 --- a/src/main/java/de/thm/arsnova/controller/v2/AuthenticationController.java +++ b/src/main/java/de/thm/arsnova/controller/v2/AuthenticationController.java @@ -285,9 +285,9 @@ public class AuthenticationController extends AbstractController { if (ldapProperties.get(0).isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "ldap", + SecurityConfig.LDAP_PROVIDER_ID, ldapProperties.get(0).getTitle(), - customizationPath + "/login?provider=ldap&redirect={0}", + customizationPath + "/login?provider=" + SecurityConfig.LDAP_PROVIDER_ID + "&redirect={0}", ldapProperties.get(0).getAllowedRoles() ); sdesc.setOrder(ldapProperties.get(0).getOrder()); @@ -296,9 +296,9 @@ public class AuthenticationController extends AbstractController { if (casProperties.isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "cas", + SecurityConfig.CAS_PROVIDER_ID, casProperties.getTitle(), - MessageFormat.format(dialogUrl, "cas"), + MessageFormat.format(dialogUrl, SecurityConfig.CAS_PROVIDER_ID), casProperties.getAllowedRoles() ); sdesc.setOrder(casProperties.getOrder()); @@ -307,45 +307,48 @@ public class AuthenticationController extends AbstractController { if (oidcProperties.get(0).isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "oidc", + SecurityConfig.OIDC_PROVIDER_ID, oidcProperties.get(0).getTitle(), - MessageFormat.format(dialogUrl, "oidc"), + MessageFormat.format(dialogUrl, SecurityConfig.OIDC_PROVIDER_ID), oidcProperties.get(0).getAllowedRoles() ); sdesc.setOrder(oidcProperties.get(0).getOrder()); services.add(sdesc); } - final AuthenticationProviderProperties.Oauth facebookProperties = oauthProperties.get("facebook"); + final AuthenticationProviderProperties.Oauth facebookProperties = + oauthProperties.get(SecurityConfig.FACEBOOK_PROVIDER_ID); if (facebookProperties != null && facebookProperties.isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "facebook", + SecurityConfig.FACEBOOK_PROVIDER_ID, "Facebook", - MessageFormat.format(dialogUrl, "facebook"), + MessageFormat.format(dialogUrl, SecurityConfig.FACEBOOK_PROVIDER_ID), facebookProperties.getAllowedRoles() ); sdesc.setOrder(facebookProperties.getOrder()); services.add(sdesc); } - final AuthenticationProviderProperties.Oauth googleProperties = oauthProperties.get("google"); + final AuthenticationProviderProperties.Oauth googleProperties = + oauthProperties.get(SecurityConfig.GOOGLE_PROVIDER_ID); if (googleProperties != null && googleProperties.isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "google", + SecurityConfig.GOOGLE_PROVIDER_ID, "Google", - MessageFormat.format(dialogUrl, "google"), + MessageFormat.format(dialogUrl, SecurityConfig.GOOGLE_PROVIDER_ID), googleProperties.getAllowedRoles() ); sdesc.setOrder(googleProperties.getOrder()); services.add(sdesc); } - final AuthenticationProviderProperties.Oauth twitterProperties = oauthProperties.get("twitter"); + final AuthenticationProviderProperties.Oauth twitterProperties = + oauthProperties.get(SecurityConfig.TWITTER_PROVIDER_ID); if (twitterProperties != null && twitterProperties.isEnabled()) { final ServiceDescription sdesc = new ServiceDescription( - "twitter", + SecurityConfig.TWITTER_PROVIDER_ID, "Twitter", - MessageFormat.format(dialogUrl, "twitter"), + MessageFormat.format(dialogUrl, SecurityConfig.TWITTER_PROVIDER_ID), twitterProperties.getAllowedRoles() ); sdesc.setOrder(twitterProperties.getOrder()); diff --git a/src/main/java/de/thm/arsnova/event/StateEventDispatcher.java b/src/main/java/de/thm/arsnova/event/StateEventDispatcher.java index 6b2a34c96b84ae7626e955b1af4df9021ea9cc60..804dc239f8a0c097fc7be88d582ac3fc30b1070e 100644 --- a/src/main/java/de/thm/arsnova/event/StateEventDispatcher.java +++ b/src/main/java/de/thm/arsnova/event/StateEventDispatcher.java @@ -37,21 +37,25 @@ import de.thm.arsnova.model.Room; */ @Component public class StateEventDispatcher implements ApplicationEventPublisherAware { + private static final String STATE_PROPERTY = "state"; + private static final String SETTINGS_PROPERTY = "settings"; + private static final String CLOSED_PROPERTY = "closed"; + private ApplicationEventPublisher eventPublisher; @EventListener public void dispatchRoomStateEvent(final AfterFullUpdateEvent<Room> event) { final Room newRoom = event.getEntity(); final Room oldRoom = event.getOldEntity(); - publishEventIfPropertyChanged(newRoom, oldRoom, Room::isClosed, "closed"); - publishEventIfPropertyChanged(newRoom, oldRoom, Room::getSettings, "settings"); + publishEventIfPropertyChanged(newRoom, oldRoom, Room::isClosed, CLOSED_PROPERTY); + publishEventIfPropertyChanged(newRoom, oldRoom, Room::getSettings, SETTINGS_PROPERTY); } @EventListener public void dispatchRoomStateEvent(final AfterPatchEvent<Room> event) { - publishEventIfPropertyChanged(event, Function.identity(), "closed", "closed"); - publishEventIfPropertyChanged(event, Function.identity(), "settings", "settings"); - publishEventIfPropertyChanged(event, Room::getSettings, null, "settings"); + publishEventIfPropertyChanged(event, Function.identity(), CLOSED_PROPERTY, CLOSED_PROPERTY); + publishEventIfPropertyChanged(event, Function.identity(), SETTINGS_PROPERTY, SETTINGS_PROPERTY); + publishEventIfPropertyChanged(event, Room::getSettings, null, SETTINGS_PROPERTY); } @EventListener @@ -60,13 +64,13 @@ public class StateEventDispatcher implements ApplicationEventPublisherAware { final Content oldContent = event.getOldEntity(); final Function<Content, Content.State> f = Content::getState; f.apply(newContent); - publishEventIfPropertyChanged(newContent, oldContent, Content::getState, "state"); + publishEventIfPropertyChanged(newContent, oldContent, Content::getState, STATE_PROPERTY); } @EventListener public void dispatchContentStateEvent(final AfterPatchEvent<Content> event) { - publishEventIfPropertyChanged(event, Function.identity(), "state", "state"); - publishEventIfPropertyChanged(event, Content::getState, null, "state"); + publishEventIfPropertyChanged(event, Function.identity(), STATE_PROPERTY, STATE_PROPERTY); + publishEventIfPropertyChanged(event, Content::getState, null, STATE_PROPERTY); } private <E extends Entity, T extends Object> void publishEventIfPropertyChanged( diff --git a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java index 573def0089110ef5c09c7bb29fd4fc78794a7e9b..5fdf7ca737aa9aa8c57c583ffd3a7b62d0963701 100644 --- a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java +++ b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java @@ -49,6 +49,11 @@ import de.thm.arsnova.persistence.RoomRepository; */ @Component public class ApplicationPermissionEvaluator implements PermissionEvaluator { + public static final String READ_PERMISSION = "read"; + public static final String CREATE_PERMISSION = "create"; + public static final String UPDATE_PERMISSION = "update"; + public static final String DELETE_PERMISSION = "delete"; + public static final String OWNER_PERMISSION = "owner"; private static final Logger logger = LoggerFactory.getLogger(ApplicationPermissionEvaluator.class); private List<String> adminAccounts; @@ -146,16 +151,16 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final UserProfile targetUserProfile, final String permission) { switch (permission) { - case "read": + case READ_PERMISSION: /* While the profile is readable for all authenticated users, it * only contains a limited amount of properties for the default * view. */ return true; - case "create": + case CREATE_PERMISSION: return true; - case "owner": - case "update": - case "delete": + case OWNER_PERMISSION: + case UPDATE_PERMISSION: + case DELETE_PERMISSION: return userId.equals(targetUserProfile.getId()); default: return false; @@ -167,15 +172,15 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final Room targetRoom, final String permission) { switch (permission) { - case "read": + case READ_PERMISSION: return !targetRoom.isClosed() || hasUserIdRoomModeratingPermission(targetRoom, userId); - case "create": + case CREATE_PERMISSION: return !userId.isEmpty(); - case "update": + case UPDATE_PERMISSION: return targetRoom.getOwnerId().equals(userId) || hasUserIdRoomModeratorRole(targetRoom, userId, Room.Moderator.Role.EDITING_MODERATOR); - case "owner": - case "delete": + case OWNER_PERMISSION: + case DELETE_PERMISSION: return targetRoom.getOwnerId().equals(userId); default: return false; @@ -192,12 +197,12 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { } switch (permission) { - case "read": + case READ_PERMISSION: return !room.isClosed() || hasUserIdRoomModeratingPermission(room, userId); - case "create": - case "update": - case "delete": - case "owner": + case CREATE_PERMISSION: + case UPDATE_PERMISSION: + case DELETE_PERMISSION: + case OWNER_PERMISSION: /* TODO: Remove owner permission for content. Use create/update/delete instead. */ return room.getOwnerId().equals(userId) || hasUserIdRoomModeratorRole(room, userId, Room.Moderator.Role.EDITING_MODERATOR); @@ -216,20 +221,20 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { } final Room room; switch (permission) { - case "read": + case READ_PERMISSION: if (targetAnswer.getCreatorId().equals(userId) || content.getState().isResponsesVisible()) { return true; } room = roomRepository.findOne(targetAnswer.getRoomId()); return room != null && hasUserIdRoomModeratingPermission(room, userId); - case "create": + case CREATE_PERMISSION: return content.getState().isResponsesEnabled(); - case "owner": + case OWNER_PERMISSION: return targetAnswer.getCreatorId().equals(userId); - case "update": + case UPDATE_PERMISSION: /* TODO */ return false; - case "delete": + case DELETE_PERMISSION: room = roomRepository.findOne(targetAnswer.getRoomId()); return room != null && hasUserIdRoomModeratingPermission(room, userId); default: @@ -242,13 +247,13 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final Comment targetComment, final String permission) { switch (permission) { - case "create": + case CREATE_PERMISSION: return !userId.isEmpty() && !roomRepository.findOne(targetComment.getRoomId()).isClosed(); - case "owner": - case "update": + case OWNER_PERMISSION: + case UPDATE_PERMISSION: return targetComment.getCreatorId() != null && targetComment.getCreatorId().equals(userId); - case "read": - case "delete": + case READ_PERMISSION: + case DELETE_PERMISSION: if (targetComment.getCreatorId() != null && targetComment.getCreatorId().equals(userId)) { return true; } @@ -268,9 +273,9 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { final String permission) { final Room room; switch (permission) { - case "create": - case "update": - case "delete": + case CREATE_PERMISSION: + case UPDATE_PERMISSION: + case DELETE_PERMISSION: if (userId.isEmpty() || targetMotd.getRoomId() == null || targetMotd.getAudience() != Motd.Audience.ROOM) { return false; } @@ -281,7 +286,7 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator { return userId.equals(room.getOwnerId()) || hasUserIdRoomModeratorRole(room, userId, Room.Moderator.Role.EDITING_MODERATOR); - case "read": + case READ_PERMISSION: if (targetMotd.getAudience() != Motd.Audience.ROOM) { return true; } diff --git a/src/main/java/de/thm/arsnova/service/UserServiceImpl.java b/src/main/java/de/thm/arsnova/service/UserServiceImpl.java index 9c399600660ef1fa1f39fe7f77bde2bd2878a4e0..10802621170b17221dd445f9933941877c717dd9 100644 --- a/src/main/java/de/thm/arsnova/service/UserServiceImpl.java +++ b/src/main/java/de/thm/arsnova/service/UserServiceImpl.java @@ -34,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import org.apache.commons.lang.CharEncoding; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -614,7 +615,7 @@ public class UserServiceImpl extends DefaultEntityServiceImpl<UserProfile> imple private void sendEmail(final UserProfile userProfile, final String subject, final String body) { final MimeMessage msg = mailSender.createMimeMessage(); - final MimeMessageHelper helper = new MimeMessageHelper(msg, "UTF-8"); + final MimeMessageHelper helper = new MimeMessageHelper(msg, CharEncoding.UTF_8); try { helper.setFrom(mailSenderName + "<" + mailSenderAddress + ">"); helper.setTo(userProfile.getLoginId()); diff --git a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java index d74a42f50d02de163b99d8ee7ec7dd08b7242949..2391cd9782b4720ef6db2571150a78eef88b976b 100644 --- a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java +++ b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java @@ -79,6 +79,32 @@ import de.thm.arsnova.websocket.message.Room; */ @Component public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { + private static final String ACTIVE_USER_COUNT_DATA_EVENTNAME = "activeUserCountData"; + private static final String SET_ROOM_ACTIVE_EVENTNAME = "setSessionActive"; + private static final String FEATURE_CHANGE_EVENTNAME = "featureChange"; + private static final String COMMENT_AVAILABLE_EVENTNAME = "audQuestionAvail"; + private static final String CONTENT_AVAILABLE_SINGLE_EVENTNAME = "lecQuestionAvail"; + private static final String CONTENT_AVAILABLE_LIST_EVENTNAME = "lecturerQuestionAvailable"; + private static final String CONTENT_LOCKED_EVENTNAME = "lecturerQuestionLocked"; + private static final String UNANSWERED_LECTURE_CONTENTS_EVENTNAME = "unansweredLecturerQuestions"; + private static final String UNANSWERED_PREPARATION_CONTENTS_EVENTNAME = "unansweredPreparationQuestions"; + private static final String ANSWERS_TO_CONTENT_AVAILABLE_EVENTNAME = "answersToLecQuestionAvail"; + private static final String COUNT_LECTURE_CONTENT_ANSWERS_EVENTNAME = "countLectureQuestionAnswers"; + private static final String COUNT_PREPARATION_CONTENT_ANSWERS_EVENTNAME = "countPreparationQuestionAnswers"; + private static final String COUNT_CONTENT_ANSWERS_BY_CONTENT_ID_EVENTNAME = "countQuestionAnswersByQuestionId"; + private static final String COUNT_FLASHCARDS_EVENTNAME = "countFlashcards"; + private static final String FLIP_FLASHCARDS_EVENTNAME = "flipFlashcards"; + private static final String FEEDBACK_DATA_EVENTNAME = "feedbackData"; + private static final String FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME = "feedbackDataRoundedAverage"; + private static final String FEEDBACK_RESET_EVENTNAME = "feedbackReset"; + private static final String LOCK_FEEDBACK_EVENTNAME = "lockFeedback"; + private static final String START_DELAYED_ROUND_EVENTNAME = "startDelayedPiRound"; + private static final String END_ROUND_EVENTNAME = "endPiRound"; + private static final String CANCEL_ROUND_EVENTNAME = "cancelPiRound"; + private static final String RESET_ROUND_EVENTNAME = "resetPiRound"; + private static final String LOCK_VOTE_EVENTNAME = "lockVote"; + private static final String UNLOCK_VOTE_EVENTNAME = "unlockVote"; + private static final String SCORE_CHANGE_EVENTNAME = "learningProgressChange"; @Autowired private FeedbackService feedbackService; @@ -349,7 +375,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { for (final de.thm.arsnova.model.Room room : rooms) { roomShortIds.add(room.getShortId()); } - this.sendToUser(userId, "feedbackReset", roomShortIds); + this.sendToUser(userId, FEEDBACK_RESET_EVENTNAME, roomShortIds); } private List<UUID> findConnectionIdForUserId(final String userId) { @@ -384,42 +410,42 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { final de.thm.arsnova.model.Room room = roomService.getInternal(roomId, userId); final de.thm.arsnova.model.Room.Settings settings = room.getSettings(); - client.sendEvent("unansweredLecturerQuestions", + client.sendEvent(UNANSWERED_LECTURE_CONTENTS_EVENTNAME, contentService.getUnAnsweredLectureContentIds(roomId, userId)); - client.sendEvent("unansweredPreparationQuestions", + client.sendEvent(UNANSWERED_PREPARATION_CONTENTS_EVENTNAME, contentService.getUnAnsweredPreparationContentIds(roomId, userId)); /* FIXME: Content variant is ignored for now */ - client.sendEvent("countLectureQuestionAnswers", answerService.countTotalAnswersByRoomId(roomId)); - client.sendEvent("countPreparationQuestionAnswers", answerService.countTotalAnswersByRoomId(roomId)); - client.sendEvent("activeUserCountData", roomService.activeUsers(roomId)); + client.sendEvent(COUNT_LECTURE_CONTENT_ANSWERS_EVENTNAME, answerService.countTotalAnswersByRoomId(roomId)); + client.sendEvent(COUNT_PREPARATION_CONTENT_ANSWERS_EVENTNAME, answerService.countTotalAnswersByRoomId(roomId)); + client.sendEvent(ACTIVE_USER_COUNT_DATA_EVENTNAME, roomService.activeUsers(roomId)); /* FIXME: missing implementation */ //client.sendEvent("learningProgressOptions", room.getLearningProgressOptions()); final de.thm.arsnova.model.Feedback fb = feedbackService.getByRoomId(roomId); - client.sendEvent("feedbackData", fb.getValues()); + client.sendEvent(FEEDBACK_DATA_EVENTNAME, fb.getValues()); if (settings.isFlashcardsEnabled()) { - client.sendEvent("countFlashcards", contentService.countFlashcardsForUserInternal(roomId)); + client.sendEvent(COUNT_FLASHCARDS_EVENTNAME, contentService.countFlashcardsForUserInternal(roomId)); /* FIXME: missing implementation */ //client.sendEvent("flipFlashcards", room.getFlipFlashcards()); } try { final long averageFeedback = feedbackService.calculateRoundedAverageFeedback(roomId); - client.sendEvent("feedbackDataRoundedAverage", averageFeedback); + client.sendEvent(FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME, averageFeedback); } catch (final NoContentException e) { final Object object = null; // can't directly use "null". - client.sendEvent("feedbackDataRoundedAverage", object); + client.sendEvent(FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME, object); } } public void reportUpdatedFeedbackForRoom(final String roomId) { final de.thm.arsnova.model.Feedback fb = feedbackService.getByRoomId(roomId); - broadcastInRoom(roomId, "feedbackData", fb.getValues()); + broadcastInRoom(roomId, FEEDBACK_DATA_EVENTNAME, fb.getValues()); try { final long averageFeedback = feedbackService.calculateRoundedAverageFeedback(roomId); - broadcastInRoom(roomId, "feedbackDataRoundedAverage", averageFeedback); + broadcastInRoom(roomId, FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME, averageFeedback); } catch (final NoContentException e) { - broadcastInRoom(roomId, "feedbackDataRoundedAverage", null); + broadcastInRoom(roomId, FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME, null); } } @@ -438,8 +464,8 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { for (final SocketIOClient client : server.getAllClients()) { if (connectionIds.contains(client.getSessionId())) { - client.sendEvent("feedbackData", fb.getValues()); - client.sendEvent("feedbackDataRoundedAverage", averageFeedback); + client.sendEvent(FEEDBACK_DATA_EVENTNAME, fb.getValues()); + client.sendEvent(FEEDBACK_DATA_ROUNDED_AVERAGE_EVENTNAME, averageFeedback); } } } @@ -447,16 +473,16 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { public void reportActiveUserCountForRoom(final String roomId) { final int count = userService.getUsersByRoomId(roomId).size(); - broadcastInRoom(roomId, "activeUserCountData", count); + broadcastInRoom(roomId, ACTIVE_USER_COUNT_DATA_EVENTNAME, count); } public void reportAnswersToContentAvailable(final String roomId, final String contentId) { - broadcastInRoom(roomId, "answersToLecQuestionAvail", contentId); + broadcastInRoom(roomId, ANSWERS_TO_CONTENT_AVAILABLE_EVENTNAME, contentId); } public void reportCommentAvailable(final String roomId, final String commentId) { /* TODO role handling implementation, send this only to users with role lecturer */ - broadcastInRoom(roomId, "audQuestionAvail", commentId); + broadcastInRoom(roomId, COMMENT_AVAILABLE_EVENTNAME, commentId); } public void reportContentAvailable(final String roomId, final List<de.thm.arsnova.model.Content> qs) { @@ -467,9 +493,9 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { /* TODO role handling implementation, send this only to users with role audience */ if (!qs.isEmpty()) { - broadcastInRoom(roomId, "lecQuestionAvail", contents.get(0).getId()); // deprecated! + broadcastInRoom(roomId, CONTENT_AVAILABLE_SINGLE_EVENTNAME, contents.get(0).getId()); // deprecated! } - broadcastInRoom(roomId, "lecturerQuestionAvailable", contents); + broadcastInRoom(roomId, CONTENT_AVAILABLE_LIST_EVENTNAME, contents); } public void reportContentsLocked(final String roomId, final List<de.thm.arsnova.model.Content> qs) { @@ -477,11 +503,11 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { for (final de.thm.arsnova.model.Content q : qs) { contents.add(new Content(q)); } - broadcastInRoom(roomId, "lecturerQuestionLocked", contents); + broadcastInRoom(roomId, CONTENT_LOCKED_EVENTNAME, contents); } public void reportRoomStatus(final String roomId, final boolean active) { - broadcastInRoom(roomId, "setSessionActive", active); + broadcastInRoom(roomId, SET_ROOM_ACTIVE_EVENTNAME, active); } public void broadcastInRoom(final String roomId, final String eventName, final Object data) { @@ -525,12 +551,12 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { public void handleNewAnswer(final AfterCreationEvent<Answer> event) { final String roomId = event.getEntity().getRoomId(); this.reportAnswersToContentAvailable(event.getEntity().getRoomId(), event.getEntity().getContentId()); - broadcastInRoom(roomId, "countQuestionAnswersByQuestionId", + broadcastInRoom(roomId, COUNT_CONTENT_ANSWERS_BY_CONTENT_ID_EVENTNAME, answerService.countAnswersAndAbstentionsInternal(event.getEntity().getContentId())); /* FIXME: Content variant is ignored for now */ - broadcastInRoom(roomId, "countLectureQuestionAnswers", + broadcastInRoom(roomId, COUNT_LECTURE_CONTENT_ANSWERS_EVENTNAME, answerService.countTotalAnswersByRoomId(roomId)); - broadcastInRoom(roomId, "countPreparationQuestionAnswers", + broadcastInRoom(roomId, COUNT_PREPARATION_CONTENT_ANSWERS_EVENTNAME, answerService.countTotalAnswersByRoomId(roomId)); // Update the unanswered count for the content variant that was answered. @@ -547,8 +573,10 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { this.reportAnswersToContentAvailable(event.getEntity().getRoomId(), event.getEntity().getContentId()); // We do not know which user's answer was deleted, so we can't update his 'unanswered' list of questions... /* FIXME: Content variant is ignored for now */ - broadcastInRoom(roomId, "countLectureQuestionAnswers", answerService.countTotalAnswersByRoomId(roomId)); - broadcastInRoom(roomId, "countPreparationQuestionAnswers", answerService.countTotalAnswersByRoomId(roomId)); + broadcastInRoom(roomId, COUNT_LECTURE_CONTENT_ANSWERS_EVENTNAME, + answerService.countTotalAnswersByRoomId(roomId)); + broadcastInRoom(roomId, COUNT_PREPARATION_CONTENT_ANSWERS_EVENTNAME, + answerService.countTotalAnswersByRoomId(roomId)); } @Async @@ -556,7 +584,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { @Timed public void handlePiRoundDelayedStart( final StateChangeEvent<de.thm.arsnova.model.Content, de.thm.arsnova.model.Content.State> event) { - broadcastInRoom(event.getEntity().getRoomId(), "startDelayedPiRound", + broadcastInRoom(event.getEntity().getRoomId(), START_DELAYED_ROUND_EVENTNAME, generateRoundInfo(event.getEntity())); } @@ -565,7 +593,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { @Timed public void handlePiRoundEnd( final StateChangeEvent<de.thm.arsnova.model.Content, de.thm.arsnova.model.Content.State> event) { - broadcastInRoom(event.getEntity().getRoomId(), "endPiRound", generateRoundInfo(event.getEntity())); + broadcastInRoom(event.getEntity().getRoomId(), END_ROUND_EVENTNAME, generateRoundInfo(event.getEntity())); } @Async @@ -573,13 +601,13 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { @Timed public void handlePiRoundCancel( final StateChangeEvent<de.thm.arsnova.model.Content, de.thm.arsnova.model.Content.State> event) { - broadcastInRoom(event.getEntity().getRoomId(), "cancelPiRound", event.getEntity().getId()); + broadcastInRoom(event.getEntity().getRoomId(), CANCEL_ROUND_EVENTNAME, event.getEntity().getId()); } @EventListener(condition = "#event.stateName == 'state'") public void handlePiRoundReset( final StateChangeEvent<de.thm.arsnova.model.Content, de.thm.arsnova.model.Content.State> event) { - broadcastInRoom(event.getEntity().getRoomId(), "resetPiRound", generateRoundInfo(event.getEntity())); + broadcastInRoom(event.getEntity().getRoomId(), RESET_ROUND_EVENTNAME, generateRoundInfo(event.getEntity())); } private Map<String, Object> generateRoundInfo(final de.thm.arsnova.model.Content content) { @@ -611,9 +639,9 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { map.put("variant", groupName); if (event.getEntity().getState().isResponsesEnabled()) { this.reportContentAvailable(event.getEntity().getRoomId(), Collections.singletonList(event.getEntity())); - broadcastInRoom(event.getEntity().getRoomId(), "unlockVote", map); + broadcastInRoom(event.getEntity().getRoomId(), UNLOCK_VOTE_EVENTNAME, map); } else { - broadcastInRoom(event.getEntity().getRoomId(), "lockVote", map); + broadcastInRoom(event.getEntity().getRoomId(), LOCK_VOTE_EVENTNAME, map); } } @@ -622,10 +650,10 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { final StateChangeEvent<de.thm.arsnova.model.Room, de.thm.arsnova.model.Room.Settings> event) { final String roomId = event.getEntity().getId(); final de.thm.arsnova.model.Room.Settings settings = event.getEntity().getSettings(); - broadcastInRoom(roomId, "featureChange", toV2Migrator.migrate(settings)); + broadcastInRoom(roomId, FEATURE_CHANGE_EVENTNAME, toV2Migrator.migrate(settings)); if (settings.isFlashcardsEnabled()) { - broadcastInRoom(roomId, "countFlashcards", + broadcastInRoom(roomId, COUNT_FLASHCARDS_EVENTNAME, contentService.countFlashcardsForUserInternal(roomId)); /* FIXME: missing implementation */ //broadcastInRoom(roomId, "flipFlashcards", event.getEntity().getSettings().isFlipFlashcards()); @@ -635,14 +663,14 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { @EventListener(condition = "#event.stateName == 'settings'") public void handleLockFeedback( final StateChangeEvent<de.thm.arsnova.model.Room, de.thm.arsnova.model.Room.Settings> event) { - broadcastInRoom(event.getEntity().getId(), "lockFeedback", + broadcastInRoom(event.getEntity().getId(), LOCK_FEEDBACK_EVENTNAME, event.getEntity().getSettings().isFeedbackLocked()); } @EventListener public void handleFlipFlashcards(final FlipFlashcardsEvent event) { /* FIXME: missing implementation */ - //broadcastInRoom(event.getRoom().getId(), "flipFlashcards", event.getRoom().getFlipFlashcards()); + //broadcastInRoom(event.getRoom().getId(), FLIP_FLASHCARDS_EVENTNAME, event.getRoom().getFlipFlashcards()); } @EventListener @@ -663,6 +691,6 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer { @EventListener public void handleChangeScore(final ChangeScoreEvent event) { - broadcastInRoom(event.getRoomId(), "learningProgressChange", null); + broadcastInRoom(event.getRoomId(), SCORE_CHANGE_EVENTNAME, null); } }