Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • arsnova/arsnova-backend
  • pcvl72/arsnova-backend
  • tksl38/arsnova-backend
3 results
Show changes
Showing
with 4303 additions and 40 deletions
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.Nullable;
import de.thm.arsnova.model.ChoiceAnswer;
import de.thm.arsnova.model.ChoiceQuestionContent;
import de.thm.arsnova.model.GridImageContent;
import de.thm.arsnova.model.TextAnswer;
import de.thm.arsnova.model.UserProfile;
import de.thm.arsnova.model.migration.v2.Answer;
import de.thm.arsnova.model.migration.v2.Comment;
import de.thm.arsnova.model.migration.v2.Content;
import de.thm.arsnova.model.migration.v2.DbUser;
import de.thm.arsnova.model.migration.v2.Entity;
import de.thm.arsnova.model.migration.v2.LoggedIn;
import de.thm.arsnova.model.migration.v2.Motd;
import de.thm.arsnova.model.migration.v2.MotdList;
import de.thm.arsnova.model.migration.v2.Room;
import de.thm.arsnova.model.migration.v2.RoomFeature;
/**
* Converts legacy entities from version 2 to current model version.
*
* @author Daniel Gerhardt
*/
public class FromV2Migrator {
static final String V2 = "v2";
static final String V2_TYPE_ABCD = "abcd";
static final String V2_TYPE_SC = "sc";
static final String V2_TYPE_MC = "mc";
static final String V2_TYPE_VOTE = "vote";
static final String V2_TYPE_SCHOOL = "school";
static final String V2_TYPE_YESNO = "yesno";
static final String V2_TYPE_FREETEXT = "freetext";
static final String V2_TYPE_SLIDE = "slide";
static final String V2_TYPE_FLASHCARD = "flashcard";
static final String V2_TYPE_GRID = "grid";
static final String V2_GRID_DEFAULT_TYPE = "image";
static final String V2_GRID_TYPE = "gridType";
static final String V2_GRID_IMAGE_ABSOLUTE_X = "gridImageAbsoluteX";
static final String V2_GRID_IMAGE_ABSOLUTE_Y = "gridImageAbsoluteY";
static final String V2_GRID_MODERATION_DOT_LIMIT = "gridModerationDotLimit";
static final int V2_GRID_CONTAINER_SIZE = 400;
static final int V2_GRID_FIELD_COUNT = 16;
static final double V2_GRID_SCALE_FACTOR = 1.05;
private static final Map<String, de.thm.arsnova.model.Content.Format> formatMapping;
private boolean ignoreRevision = false;
static {
formatMapping = new HashMap<>();
formatMapping.put(V2_TYPE_ABCD, de.thm.arsnova.model.Content.Format.CHOICE);
formatMapping.put(V2_TYPE_SC, de.thm.arsnova.model.Content.Format.CHOICE);
formatMapping.put(V2_TYPE_MC, de.thm.arsnova.model.Content.Format.CHOICE);
formatMapping.put(V2_TYPE_VOTE, de.thm.arsnova.model.Content.Format.SCALE);
formatMapping.put(V2_TYPE_SCHOOL, de.thm.arsnova.model.Content.Format.SCALE);
formatMapping.put(V2_TYPE_YESNO, de.thm.arsnova.model.Content.Format.BINARY);
formatMapping.put(V2_TYPE_FREETEXT, de.thm.arsnova.model.Content.Format.TEXT);
formatMapping.put(V2_TYPE_SLIDE, de.thm.arsnova.model.Content.Format.TEXT);
formatMapping.put(V2_TYPE_FLASHCARD, de.thm.arsnova.model.Content.Format.TEXT);
formatMapping.put(V2_TYPE_GRID, de.thm.arsnova.model.Content.Format.GRID);
}
private void copyCommonProperties(final Entity from, final de.thm.arsnova.model.Entity to) {
to.setId(from.getId());
if (!ignoreRevision) {
to.setRevision(from.getRevision());
}
}
public UserProfile migrate(final DbUser dbUser, final LoggedIn loggedIn, final MotdList motdList) {
if (dbUser != null && loggedIn != null && !loggedIn.getUser().equals(dbUser.getUsername())) {
throw new IllegalArgumentException("Username of loggedIn object does not match.");
}
if (dbUser != null && motdList != null && !motdList.getUsername().equals(dbUser.getUsername())) {
throw new IllegalArgumentException("Username of motdList object does not match.");
}
if (loggedIn != null && motdList != null && !loggedIn.getUser().equals(motdList.getUsername())) {
throw new IllegalArgumentException("Usernames of loggedIn and motdList objects do not match.");
}
final UserProfile profile = new UserProfile();
if (dbUser != null) {
copyCommonProperties(dbUser, profile);
profile.setLoginId(dbUser.getUsername());
profile.setAuthProvider(UserProfile.AuthProvider.ARSNOVA);
profile.setCreationTimestamp(new Date(dbUser.getCreation()));
profile.setUpdateTimestamp(new Date());
final UserProfile.Account account = new UserProfile.Account();
profile.setAccount(account);
account.setPassword(dbUser.getPassword());
account.setActivationKey(dbUser.getActivationKey());
account.setPasswordResetKey(dbUser.getPasswordResetKey());
account.setPasswordResetTime(new Date(dbUser.getPasswordResetTime()));
}
if (loggedIn != null) {
if (dbUser == null) {
copyCommonProperties(loggedIn, profile);
updateProfileFromLoginId(profile, loggedIn.getUser());
profile.setCreationTimestamp(new Date());
}
profile.setLastLoginTimestamp(new Date(loggedIn.getTimestamp()));
final Set<UserProfile.RoomHistoryEntry> sessionHistory = loggedIn.getVisitedSessions().stream()
.map(entry -> new UserProfile.RoomHistoryEntry(entry.getId(), new Date(0)))
.collect(Collectors.toSet());
profile.setRoomHistory(sessionHistory);
}
if (motdList != null && motdList.getMotdkeys() != null) {
profile.setAcknowledgedMotds(migrate(motdList));
}
return profile;
}
public Set<String> migrate(final MotdList motdList) {
return Arrays.stream(motdList.getMotdkeys().split(",")).collect(Collectors.toSet());
}
public de.thm.arsnova.model.Room migrate(final Room from, final Optional<UserProfile> owner) {
if (!owner.isPresent() && from.getCreator() != null
|| owner.isPresent() && !owner.get().getLoginId().equals(from.getCreator())) {
throw new IllegalArgumentException("Username of owner object does not match session creator.");
}
final de.thm.arsnova.model.Room to = new de.thm.arsnova.model.Room();
copyCommonProperties(from, to);
to.setCreationTimestamp(new Date(from.getCreationTime()));
to.setUpdateTimestamp(new Date());
to.setShortId(from.getKeyword());
if (owner.isPresent()) {
to.setOwnerId(owner.get().getId());
}
to.setName(from.getName());
to.setAbbreviation(from.getShortName());
to.setDescription(from.getPpDescription());
to.setClosed(!from.isActive());
if (from.hasAuthorDetails()) {
final de.thm.arsnova.model.Room.Author author = new de.thm.arsnova.model.Room.Author();
to.setAuthor(author);
author.setName(from.getPpAuthorName());
author.setMail(from.getPpAuthorMail());
author.setOrganizationName(from.getPpUniversity());
author.setOrganizationUnit(from.getPpFaculty());
author.setOrganizationLogo(from.getPpLogo());
}
if ("public_pool".equals(from.getSessionType())) {
final de.thm.arsnova.model.Room.PoolProperties poolProperties = new de.thm.arsnova.model.Room.PoolProperties();
to.setPoolProperties(poolProperties);
poolProperties.setLevel(from.getPpLevel());
poolProperties.setCategory(from.getPpSubject());
poolProperties.setLicense(from.getPpLicense());
}
to.setSettings(migrate(from.getFeatures()));
return to;
}
public de.thm.arsnova.model.Room migrate(final Room from) {
return migrate(from, Optional.empty());
}
public de.thm.arsnova.model.Room.Settings migrate(final RoomFeature feature) {
final de.thm.arsnova.model.Room.Settings settings = new de.thm.arsnova.model.Room.Settings();
if (feature != null) {
settings.setCommentsEnabled(feature.isInterposed() || feature.isInterposedFeedback()
|| feature.isTwitterWall() || feature.isTotal());
settings.setQuestionsEnabled(feature.isLecture() || feature.isJitt() || feature.isClicker() || feature.isTotal());
settings.setSlidesEnabled(feature.isSlides() || feature.isTotal());
settings.setFlashcardsEnabled(feature.isFlashcardFeature() || feature.isFlashcard() || feature.isTotal());
settings.setQuickSurveyEnabled(feature.isLiveClicker());
settings.setQuickFeedbackEnabled(feature.isFeedback() || feature.isLiveFeedback() || feature.isTotal());
settings.setMultipleRoundsEnabled(feature.isPi() || feature.isClicker() || feature.isTotal());
settings.setTimerEnabled(feature.isPi() || feature.isClicker() || feature.isTotal());
settings.setScoreEnabled(feature.isLearningProgress() || feature.isTotal());
}
return settings;
}
public de.thm.arsnova.model.Content migrate(final Content from) {
final de.thm.arsnova.model.Content to;
final Map<String, Map<String, Object>> extensions;
final Map<String, Object> v2;
switch (from.getQuestionType()) {
case V2_TYPE_ABCD:
case V2_TYPE_SC:
case V2_TYPE_MC:
case V2_TYPE_VOTE:
case V2_TYPE_SCHOOL:
case V2_TYPE_YESNO:
final ChoiceQuestionContent choiceQuestionContent = new ChoiceQuestionContent();
to = choiceQuestionContent;
to.setFormat(formatMapping.get(from.getQuestionType()));
choiceQuestionContent.setMultiple(V2_TYPE_MC.equals(from.getQuestionType()));
for (int i = 0; i < from.getPossibleAnswers().size(); i++) {
final de.thm.arsnova.model.migration.v2.AnswerOption fromOption = from.getPossibleAnswers().get(i);
final ChoiceQuestionContent.AnswerOption toOption = new ChoiceQuestionContent.AnswerOption();
toOption.setLabel(fromOption.getText());
toOption.setPoints(fromOption.getValue());
choiceQuestionContent.getOptions().add(toOption);
if (fromOption.isCorrect()) {
choiceQuestionContent.getCorrectOptionIndexes().add(i);
}
}
break;
case V2_TYPE_FREETEXT:
to = new de.thm.arsnova.model.Content();
to.setFormat(de.thm.arsnova.model.Content.Format.TEXT);
break;
case V2_TYPE_SLIDE:
to = new de.thm.arsnova.model.Content();
to.setFormat(de.thm.arsnova.model.Content.Format.TEXT);
extensions = new HashMap<>();
to.setExtensions(extensions);
v2 = new HashMap<>();
extensions.put("v2", v2);
v2.put("format", V2_TYPE_SLIDE);
break;
case V2_TYPE_FLASHCARD:
to = new de.thm.arsnova.model.Content();
to.setFormat(de.thm.arsnova.model.Content.Format.TEXT);
extensions = new HashMap<>();
to.setExtensions(extensions);
v2 = new HashMap<>();
extensions.put("v2", v2);
v2.put("format", V2_TYPE_FLASHCARD);
if (!from.getPossibleAnswers().isEmpty()) {
to.setAdditionalText(from.getPossibleAnswers().get(0).getText());
to.setAdditionalTextTitle("Back");
}
break;
case V2_TYPE_GRID:
final GridImageContent gridImageContent = new GridImageContent();
to = gridImageContent;
to.setFormat(de.thm.arsnova.model.Content.Format.GRID);
final GridImageContent.Grid grid = gridImageContent.getGrid();
grid.setColumns(from.getGridSizeX());
grid.setRows(from.getGridSizeY());
grid.setNormalizedX(1.0 * from.getGridOffsetX() / V2_GRID_CONTAINER_SIZE);
grid.setNormalizedY(1.0 * from.getGridOffsetY() / V2_GRID_CONTAINER_SIZE);
/* v3 normalized field size = v2 scale factor ^ v2 zoom level / v2 grid size */
grid.setNormalizedFieldSize(Math.pow(Double.valueOf(from.getGridScaleFactor()), from.getGridZoomLvl())
/ from.getGridSize());
grid.setVisible(!from.getGridIsHidden());
final GridImageContent.Image image = gridImageContent.getImage();
image.setUrl(from.getImage());
image.setRotation(from.getImgRotation() * 90 % 360);
image.setScaleFactor(Math.pow(Double.valueOf(from.getScaleFactor()), from.getZoomLvl()));
gridImageContent.setCorrectOptionIndexes(from.getPossibleAnswers().stream()
.filter(o -> o.isCorrect())
.map(o -> {
try {
final String[] coords = (o.getText() != null ? o.getText() : "").split(";");
return coords.length == 2
? Integer.valueOf(coords[0]) + Integer.valueOf(coords[1]) * from.getGridSizeX()
: -1;
} catch (final NumberFormatException e) {
return -1;
}
})
.filter(i -> i >= 0 && i < grid.getColumns() * grid.getRows())
.collect(Collectors.toList()));
extensions = new HashMap<>();
to.setExtensions(extensions);
v2 = new HashMap<>();
extensions.put(V2, v2);
v2.put(V2_GRID_TYPE, from.getGridType());
/* It is not possible to migrate legacy image offsets to normalized values. */
if (from.getOffsetX() != 0) {
v2.put(V2_GRID_IMAGE_ABSOLUTE_X, from.getOffsetX());
}
if (from.getOffsetY() != 0) {
v2.put(V2_GRID_IMAGE_ABSOLUTE_Y, from.getOffsetY());
}
if (from.getNumberOfDots() != 0) {
v2.put(V2_GRID_MODERATION_DOT_LIMIT, from.getNumberOfDots());
}
break;
default:
throw new IllegalArgumentException("Unsupported content format.");
}
copyCommonProperties(from, to);
to.setRoomId(from.getSessionId());
to.getGroups().add(from.getQuestionVariant());
to.setSubject(from.getSubject());
to.setBody(from.getText());
to.setAbstentionsAllowed(from.isAbstention());
to.setAbstentionsAllowed(from.isAbstention());
if (from.getSolution() != null && !from.getSolution().isEmpty()) {
to.setAdditionalText(from.getSolution());
to.setAdditionalTextTitle("Solution");
} else if (from.getHint() != null && !from.getHint().isEmpty()) {
to.setAdditionalText(from.getHint());
to.setAdditionalTextTitle("Hint");
}
final de.thm.arsnova.model.Content.State state = to.getState();
state.setRound(from.getPiRound());
state.setVisible(from.isActive());
state.setResponsesVisible(from.isShowStatistic());
state.setAdditionalTextVisible(from.isShowAnswer());
state.setResponsesEnabled(!from.isVotingDisabled());
return to;
}
public de.thm.arsnova.model.Answer migrate(final Answer from, final de.thm.arsnova.model.Content content) {
final de.thm.arsnova.model.Answer answer;
if (content instanceof ChoiceQuestionContent || content instanceof GridImageContent) {
answer = migrateChoice(from, content);
} else {
answer = migrate(from);
}
answer.setFormat(content.getFormat());
return answer;
}
public TextAnswer migrate(final Answer from) {
final TextAnswer to = new TextAnswer();
copyCommonProperties(from, to);
to.setContentId(from.getQuestionId());
to.setRoomId(from.getSessionId());
to.setRound(from.getPiRound());
to.setSubject(from.getAnswerSubject());
to.setBody(from.getAnswerText());
return to;
}
public de.thm.arsnova.model.Comment migrate(final Comment from, @Nullable final UserProfile creator) {
if (creator == null && from.getCreator() != null
|| creator != null && !creator.getLoginId().equals(from.getCreator())) {
throw new IllegalArgumentException("Username of creator object does not match comment creator.");
}
final de.thm.arsnova.model.Comment to = new de.thm.arsnova.model.Comment();
copyCommonProperties(from, to);
to.setRoomId(from.getSessionId());
if (creator != null) {
to.setCreatorId(creator.getId());
}
to.setSubject(from.getSubject());
to.setBody(from.getText());
to.setTimestamp(new Date(from.getTimestamp()));
to.setRead(from.isRead());
return to;
}
public de.thm.arsnova.model.Comment migrate(final Comment from) {
return migrate(from, null);
}
public de.thm.arsnova.model.Motd migrate(final Motd from) {
final de.thm.arsnova.model.Motd to = new de.thm.arsnova.model.Motd();
copyCommonProperties(from, to);
to.setCreationTimestamp(from.getStartdate());
to.setUpdateTimestamp(new Date());
to.setStartDate(from.getStartdate());
to.setEndDate(from.getEnddate());
switch (from.getAudience()) {
case "all":
to.setAudience(de.thm.arsnova.model.Motd.Audience.ALL);
break;
case "tutors":
to.setAudience(de.thm.arsnova.model.Motd.Audience.AUTHORS);
break;
case "students":
to.setAudience(de.thm.arsnova.model.Motd.Audience.PARTICIPANTS);
break;
case "session":
to.setAudience(de.thm.arsnova.model.Motd.Audience.ROOM);
break;
default:
/* TODO: Add log message. */
break;
}
to.setTitle(from.getTitle());
to.setBody(from.getText());
to.setRoomId(from.getSessionId());
return to;
}
private ChoiceAnswer migrateChoice(final Answer from, final de.thm.arsnova.model.Content content) {
final ChoiceAnswer to = new ChoiceAnswer();
copyCommonProperties(from, to);
to.setContentId(from.getQuestionId());
to.setRoomId(from.getSessionId());
to.setRound(from.getPiRound());
if (from.isAbstention()) {
return to;
}
if (content instanceof ChoiceQuestionContent) {
final List<Integer> selectedChoiceIndexes = new ArrayList<>();
to.setSelectedChoiceIndexes(selectedChoiceIndexes);
final ChoiceQuestionContent choiceQuestionContent = (ChoiceQuestionContent) content;
if (choiceQuestionContent.isMultiple()) {
final List<Boolean> flags = Arrays.stream(from.getAnswerText().split(","))
.map("1"::equals).collect(Collectors.toList());
if (flags.size() != choiceQuestionContent.getOptions().size()) {
throw new IndexOutOfBoundsException(
"Number of answer's choice flags does not match number of content's answer options");
}
int i = 0;
for (final boolean flag : flags) {
if (flag) {
selectedChoiceIndexes.add(i);
}
i++;
}
} else {
int i = 0;
for (final ChoiceQuestionContent.AnswerOption option : choiceQuestionContent.getOptions()) {
if (option.getLabel().equals(from.getAnswerText())) {
selectedChoiceIndexes.add(i);
break;
}
i++;
}
}
} else if (content instanceof GridImageContent) {
final GridImageContent gridImageContent = (GridImageContent) content;
to.setSelectedChoiceIndexes(migrateChoice(from.getAnswerText(), gridImageContent.getGrid()));
} else {
throw new IllegalArgumentException(
"Content expected to be an instance of ChoiceQuestionContent or GridImageContent");
}
return to;
}
private List<Integer> migrateChoice(final String choice, final GridImageContent.Grid grid) {
return Arrays.stream(choice.split(","))
.map(c -> {
try {
final String[] coords = c.split(";");
return coords.length == 2
? Integer.valueOf(coords[0])
+ Integer.valueOf(coords[1]) * grid.getColumns()
: -1;
} catch (final NumberFormatException e) {
return -1;
}
})
.filter(i -> i >= 0
&& i < grid.getColumns() * grid.getRows())
.collect(Collectors.toList());
}
private void updateProfileFromLoginId(final UserProfile profile, final String loginId) {
if (loginId.length() == 15 && loginId.startsWith("Guest")) {
profile.setAuthProvider(UserProfile.AuthProvider.ARSNOVA_GUEST);
profile.setLoginId(loginId);
} else if (loginId.startsWith("$")) {
profile.setAuthProvider(UserProfile.AuthProvider.ANONYMIZED);
/* Remove redundant prefix and shorten ID to 10 chars */
profile.setLoginId(loginId.substring(loginId.lastIndexOf("$") + 1).substring(0, 10));
} else if (loginId.startsWith("oidc:")) {
profile.setAuthProvider(UserProfile.AuthProvider.OIDC);
profile.setLoginId(loginId.substring(5));
} else if (loginId.startsWith("saml:")) {
profile.setAuthProvider(UserProfile.AuthProvider.SAML);
profile.setLoginId(loginId.substring(5));
} else if (loginId.startsWith("https://www.facebook.com/") || loginId.startsWith("http://www.facebook.com/")) {
profile.setAuthProvider(UserProfile.AuthProvider.FACEBOOK);
/* Extract ID from URL */
profile.setLoginId(loginId.substring(loginId.indexOf("/", 23) + 1, loginId.length() - 1));
} else if (loginId.contains("@")) {
profile.setAuthProvider(UserProfile.AuthProvider.GOOGLE);
profile.setLoginId(loginId);
} else {
profile.setAuthProvider(UserProfile.AuthProvider.UNKNOWN);
profile.setLoginId(loginId);
}
}
public void setIgnoreRevision(final boolean ignoreRevision) {
this.ignoreRevision = ignoreRevision;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_CONTAINER_SIZE;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_DEFAULT_TYPE;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_FIELD_COUNT;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_IMAGE_ABSOLUTE_X;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_IMAGE_ABSOLUTE_Y;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_MODERATION_DOT_LIMIT;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_SCALE_FACTOR;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_GRID_TYPE;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_ABCD;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_FLASHCARD;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_FREETEXT;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_GRID;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_MC;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_SCHOOL;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_SLIDE;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_VOTE;
import static de.thm.arsnova.model.migration.FromV2Migrator.V2_TYPE_YESNO;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import de.thm.arsnova.model.AnswerStatistics;
import de.thm.arsnova.model.ChoiceQuestionContent;
import de.thm.arsnova.model.GridImageContent;
import de.thm.arsnova.model.RoomStatistics;
import de.thm.arsnova.model.UserProfile;
import de.thm.arsnova.model.migration.v2.Answer;
import de.thm.arsnova.model.migration.v2.AnswerOption;
import de.thm.arsnova.model.migration.v2.Comment;
import de.thm.arsnova.model.migration.v2.Content;
import de.thm.arsnova.model.migration.v2.Entity;
import de.thm.arsnova.model.migration.v2.LoggedIn;
import de.thm.arsnova.model.migration.v2.Motd;
import de.thm.arsnova.model.migration.v2.MotdList;
import de.thm.arsnova.model.migration.v2.Room;
import de.thm.arsnova.model.migration.v2.RoomFeature;
import de.thm.arsnova.model.migration.v2.RoomInfo;
import de.thm.arsnova.model.migration.v2.VisitedRoom;
/**
* Converts entities from current model version to legacy version 2.
*
* @author Daniel Gerhardt
*/
public class ToV2Migrator {
private void copyCommonProperties(final de.thm.arsnova.model.Entity from, final Entity to) {
to.setId(from.getId());
to.setRevision(from.getRevision());
}
public Room migrate(final de.thm.arsnova.model.Room from, final Optional<UserProfile> owner) {
final Room to = new Room();
copyCommonProperties(from, to);
to.setKeyword(from.getShortId());
if (owner.isPresent()) {
to.setCreator(owner.get().getLoginId());
}
to.setName(from.getName());
to.setShortName(from.getAbbreviation());
to.setActive(!from.isClosed());
if (from.getAuthor() != null) {
to.setPpAuthorName(from.getAuthor().getName());
to.setPpAuthorMail(from.getAuthor().getMail());
to.setPpUniversity(from.getAuthor().getOrganizationName());
to.setPpFaculty(from.getAuthor().getOrganizationUnit());
to.setPpLogo(from.getAuthor().getOrganizationLogo());
}
to.setFeatures(migrate(from.getSettings()));
return to;
}
public Room migrate(final de.thm.arsnova.model.Room from) {
return migrate(from, Optional.empty());
}
public RoomFeature migrate(final de.thm.arsnova.model.Room.Settings settings) {
final RoomFeature feature = new RoomFeature();
/* Features */
feature.setInterposed(settings.isCommentsEnabled());
feature.setLecture(settings.isQuestionsEnabled());
feature.setJitt(settings.isQuestionsEnabled());
feature.setSlides(settings.isSlidesEnabled());
feature.setFlashcardFeature(settings.isFlashcardsEnabled());
feature.setFeedback(settings.isQuickFeedbackEnabled());
feature.setPi(settings.isMultipleRoundsEnabled() || settings.isTimerEnabled());
feature.setLearningProgress(settings.isScoreEnabled());
/* Use cases */
int count = 0;
/* Single-feature use cases can be migrated */
if (settings.isCommentsEnabled()) {
feature.setInterposedFeedback(true);
count++;
}
if (settings.isFlashcardsEnabled()) {
feature.setFlashcard(true);
count++;
}
if (settings.isQuickFeedbackEnabled()) {
feature.setLiveFeedback(true);
count++;
}
if (settings.isQuickSurveyEnabled()) {
feature.setLiveClicker(true);
count++;
}
/* For the following features an exact migration is not possible, so custom is set */
if (settings.isQuestionsEnabled()) {
feature.setCustom(true);
count++;
}
if (settings.isSlidesEnabled()) {
feature.setCustom(true);
count++;
}
if (settings.isMultipleRoundsEnabled() || settings.isTimerEnabled()) {
feature.setCustom(true);
count++;
}
if (settings.isScoreEnabled()) {
feature.setCustom(true);
count++;
}
if (count != 1) {
/* Reset single-feature use-cases since multiple features were detected */
feature.setInterposedFeedback(false);
feature.setFlashcard(false);
feature.setLiveFeedback(false);
feature.setLiveClicker(false);
if (count == 7) {
feature.setCustom(false);
feature.setTotal(true);
} else {
feature.setCustom(true);
}
}
return feature;
}
public Content migrate(final de.thm.arsnova.model.Content from) {
final Content to = new Content();
copyCommonProperties(from, to);
to.setSessionId(from.getRoomId());
to.setSubject(from.getSubject());
to.setText(from.getBody());
to.setAbstention(from.isAbstentionsAllowed());
if (!from.getState().isAdditionalTextVisible() || "Solution".equals(from.getAdditionalTextTitle())) {
to.setSolution(from.getAdditionalText());
} else if (from.getAdditionalText() != null) {
to.setHint(from.getAdditionalText());
}
if (from instanceof ChoiceQuestionContent) {
final ChoiceQuestionContent fromChoiceQuestionContent = (ChoiceQuestionContent) from;
switch (from.getFormat()) {
case CHOICE:
to.setQuestionType(fromChoiceQuestionContent.isMultiple() ? V2_TYPE_MC : V2_TYPE_ABCD);
break;
case BINARY:
to.setQuestionType(V2_TYPE_YESNO);
break;
case SCALE:
final int optionCount = fromChoiceQuestionContent.getOptions().size();
/* The number of options for vote/school format is hard-coded by the legacy client */
if (optionCount == 5) {
to.setQuestionType(V2_TYPE_VOTE);
} else if (optionCount == 6) {
to.setQuestionType(V2_TYPE_SCHOOL);
} else {
to.setQuestionType(V2_TYPE_ABCD);
}
break;
case GRID:
to.setQuestionType(V2_TYPE_GRID);
break;
default:
throw new IllegalArgumentException("Unsupported content format.");
}
final List<AnswerOption> toOptions = new ArrayList<>();
to.setPossibleAnswers(toOptions);
for (int i = 0; i < fromChoiceQuestionContent.getOptions().size(); i++) {
final AnswerOption option = new AnswerOption();
option.setText(fromChoiceQuestionContent.getOptions().get(i).getLabel());
option.setValue(fromChoiceQuestionContent.getOptions().get(i).getPoints());
option.setCorrect(fromChoiceQuestionContent.getCorrectOptionIndexes().contains(i));
toOptions.add(option);
}
} else {
switch (from.getFormat()) {
case NUMBER:
to.setQuestionType(V2_TYPE_FREETEXT);
break;
case TEXT:
final String legacyType = from.getExtensions() != null
? (String) from.getExtensions()
.getOrDefault("v2", Collections.emptyMap()).getOrDefault("format", "")
: "";
switch (legacyType) {
case V2_TYPE_SLIDE:
to.setQuestionType(V2_TYPE_SLIDE);
break;
case V2_TYPE_FLASHCARD:
to.setQuestionType(V2_TYPE_FLASHCARD);
final AnswerOption back = new AnswerOption();
back.setText(from.getAdditionalText());
back.setCorrect(true);
to.setPossibleAnswers(Collections.singletonList(back));
break;
default:
to.setQuestionType(V2_TYPE_FREETEXT);
break;
}
break;
case GRID:
final GridImageContent fromGridImageContent = (GridImageContent) from;
final GridImageContent.Grid grid = fromGridImageContent.getGrid();
final GridImageContent.Image image = fromGridImageContent.getImage();
to.setQuestionType(V2_TYPE_GRID);
to.setGridSizeX(grid.getColumns());
to.setGridSizeY(grid.getRows());
to.setGridOffsetX((int) (Math.round(grid.getNormalizedX() * V2_GRID_CONTAINER_SIZE)));
to.setGridOffsetY((int) (Math.round(grid.getNormalizedY() * V2_GRID_CONTAINER_SIZE)));
/* v3 normalized field size = v2 scale factor ^ v2 zoom level / v2 grid size */
to.setGridSize(V2_GRID_FIELD_COUNT);
to.setGridScaleFactor(String.valueOf(V2_GRID_SCALE_FACTOR));
to.setGridZoomLvl((int) Math.round(
Math.log(grid.getNormalizedFieldSize() * V2_GRID_FIELD_COUNT)
/ Math.log(V2_GRID_SCALE_FACTOR)));
to.setGridIsHidden(!grid.isVisible());
to.setImage(image.getUrl());
to.setImgRotation(image.getRotation() / 90 % 4);
to.setScaleFactor(String.valueOf(V2_GRID_SCALE_FACTOR));
to.setZoomLvl((int) Math.round(
Math.log(image.getScaleFactor()) / Math.log(V2_GRID_SCALE_FACTOR)));
to.setPossibleAnswers(
fromGridImageContent.getCorrectOptionIndexes().stream()
.map(i -> {
final int x = i % fromGridImageContent.getGrid().getColumns();
final int y = i / fromGridImageContent.getGrid().getColumns();
final AnswerOption answerOption = new AnswerOption();
answerOption.setText(x + ";" + y);
answerOption.setCorrect(true);
return answerOption;
})
.collect(Collectors.toList()));
if (fromGridImageContent.getExtensions() != null) {
final Map<String, Object> v2 = fromGridImageContent.getExtensions()
.getOrDefault(V2, Collections.emptyMap());
to.setGridType((String) v2.getOrDefault(V2_GRID_TYPE, V2_GRID_DEFAULT_TYPE));
to.setOffsetX((int) v2.getOrDefault(V2_GRID_IMAGE_ABSOLUTE_X, 0));
to.setOffsetY((int) v2.getOrDefault(V2_GRID_IMAGE_ABSOLUTE_Y, 0));
to.setNumberOfDots((int) v2.getOrDefault(V2_GRID_MODERATION_DOT_LIMIT, 0));
} else {
to.setGridType(V2_GRID_DEFAULT_TYPE);
}
break;
default:
throw new IllegalArgumentException("Unsupported content format.");
}
}
final de.thm.arsnova.model.Content.State state = from.getState();
to.setPiRound(state.getRound());
to.setActive(state.isVisible());
to.setShowStatistic(state.isResponsesVisible());
to.setShowAnswer(state.isAdditionalTextVisible());
to.setVotingDisabled(!state.isResponsesEnabled());
if (from.getGroups().size() == 1) {
to.setQuestionVariant(from.getGroups().iterator().next());
}
return to;
}
public Answer migrate(final de.thm.arsnova.model.ChoiceAnswer from,
final de.thm.arsnova.model.Content content, final Optional<UserProfile> creator) {
final Answer to = new Answer();
copyCommonProperties(from, to);
to.setQuestionId(from.getContentId());
to.setSessionId(from.getRoomId());
to.setPiRound(from.getRound());
if (creator.isPresent()) {
to.setUser(creator.get().getLoginId());
}
if (from.getSelectedChoiceIndexes().isEmpty()) {
to.setAbstention(true);
} else {
if (content instanceof ChoiceQuestionContent) {
final ChoiceQuestionContent choiceQuestionContent = (ChoiceQuestionContent) content;
if (choiceQuestionContent.isMultiple()) {
to.setAnswerText(migrateChoice(from.getSelectedChoiceIndexes(),
choiceQuestionContent.getOptions()));
} else {
final int index = from.getSelectedChoiceIndexes().get(0);
to.setAnswerText(choiceQuestionContent.getOptions().get(index).getLabel());
}
} else if (content instanceof GridImageContent) {
final GridImageContent gridImageContent = (GridImageContent) content;
to.setAnswerText(migrateChoice(from.getSelectedChoiceIndexes(), gridImageContent.getGrid()));
} else {
throw new IllegalArgumentException(
"Content expected to be an instance of ChoiceQuestionContent or GridImageContent");
}
}
return to;
}
public Answer migrate(final de.thm.arsnova.model.ChoiceAnswer from,
final de.thm.arsnova.model.Content content) {
return migrate(from, content, Optional.empty());
}
public Answer migrate(final de.thm.arsnova.model.TextAnswer from,
final Optional<de.thm.arsnova.model.Content> content, final Optional<UserProfile> creator) {
final Answer to = new Answer();
copyCommonProperties(from, to);
to.setQuestionId(from.getContentId());
to.setSessionId(from.getRoomId());
to.setPiRound(from.getRound());
if (creator.isPresent()) {
to.setUser(creator.get().getLoginId());
}
to.setAnswerSubject(from.getSubject());
to.setAnswerText(from.getBody());
return to;
}
public Answer migrate(final de.thm.arsnova.model.TextAnswer from) {
return migrate(from, Optional.empty(), Optional.empty());
}
public Comment migrate(final de.thm.arsnova.model.Comment from, final Optional<UserProfile> creator) {
final Comment to = new Comment();
copyCommonProperties(from, to);
to.setSessionId(from.getRoomId());
if (creator.isPresent()) {
to.setCreator(creator.get().getLoginId());
}
to.setSubject(from.getSubject());
to.setText(from.getBody());
to.setTimestamp(from.getTimestamp().getTime());
to.setRead(from.isRead());
return to;
}
public Comment migrate(final de.thm.arsnova.model.Comment from) {
return migrate(from, Optional.empty());
}
public Motd migrate(final de.thm.arsnova.model.Motd from) {
final Motd to = new Motd();
copyCommonProperties(from, to);
to.setMotdkey(from.getId());
to.setStartdate(from.getCreationTimestamp());
to.setStartdate(from.getStartDate());
to.setEnddate(from.getEndDate());
switch (from.getAudience()) {
case ALL:
to.setAudience("all");
break;
case AUTHORS:
to.setAudience("tutors");
break;
case PARTICIPANTS:
to.setAudience("students");
break;
case ROOM:
to.setAudience("session");
break;
default:
break;
}
to.setTitle(from.getTitle());
to.setText(from.getBody());
to.setSessionId(from.getRoomId());
return to;
}
public List<Answer> migrate(final AnswerStatistics from,
final de.thm.arsnova.model.Content content, final int round) {
if (round < 1 || round > content.getState().getRound()) {
throw new IllegalArgumentException("Invalid value for round");
}
final List<Answer> to = new ArrayList<>();
final AnswerStatistics.RoundStatistics stats = from.getRoundStatistics().get(round - 1);
if (content.isAbstentionsAllowed()) {
final Answer abstention = new Answer();
abstention.setQuestionId(content.getId());
abstention.setPiRound(round);
abstention.setAnswerCount(stats.getAbstentionCount());
abstention.setAbstentionCount(stats.getAbstentionCount());
to.add(abstention);
}
final Map<String, Integer> choices;
if (content instanceof ChoiceQuestionContent) {
final ChoiceQuestionContent choiceQuestionContent = (ChoiceQuestionContent) content;
if (choiceQuestionContent.isMultiple()) {
/* Map selected choice indexes -> answer count */
choices = stats.getCombinatedCounts().stream().collect(Collectors.toMap(
c -> migrateChoice(c.getSelectedChoiceIndexes(), choiceQuestionContent.getOptions()),
c -> c.getCount(),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
} else {
choices = new LinkedHashMap<>();
int i = 0;
for (final ChoiceQuestionContent.AnswerOption option : choiceQuestionContent.getOptions()) {
choices.put(option.getLabel(), stats.getIndependentCounts().get(i));
i++;
}
}
} else {
final GridImageContent gridImageContent = (GridImageContent) content;
choices = stats.getCombinatedCounts().stream().collect(Collectors.toMap(
c -> migrateChoice(c.getSelectedChoiceIndexes(), gridImageContent.getGrid()),
c -> c.getCount(),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
}
for (final Map.Entry<String, Integer> choice : choices.entrySet()) {
final Answer answer = new Answer();
answer.setQuestionId(content.getId());
answer.setPiRound(round);
answer.setAnswerCount(choice.getValue());
answer.setAbstentionCount(stats.getAbstentionCount());
answer.setAnswerText(choice.getKey());
to.add(answer);
}
return to;
}
public LoggedIn migrateLoggedIn(final UserProfile from) {
final LoggedIn to = new LoggedIn();
copyCommonProperties(from, to);
to.setUser(from.getLoginId());
to.setTimestamp(from.getLastLoginTimestamp().getTime());
to.setVisitedSessions(from.getRoomHistory().stream()
.map(entry -> new VisitedRoom())
.collect(Collectors.toList()));
return to;
}
public MotdList migrateMotdList(final UserProfile from) {
final MotdList to = new MotdList();
copyCommonProperties(from, to);
to.setUsername(from.getLoginId());
to.setMotdkeys(String.join(",", from.getAcknowledgedMotds()));
return to;
}
public RoomInfo migrateStats(final de.thm.arsnova.model.Room from) {
final RoomInfo to = new RoomInfo(migrate(from));
final RoomStatistics stats = from.getStatistics();
to.setNumQuestions(stats.getContentCount());
to.setNumUnanswered(stats.getUnansweredContentCount());
to.setNumAnswers(stats.getAnswerCount());
to.setNumInterposed(stats.getCommentCount());
to.setNumUnredInterposed(stats.getUnreadCommentCount());
return to;
}
private String migrateChoice(final List<Integer> selectedChoiceIndexes,
final List<ChoiceQuestionContent.AnswerOption> options) {
final List<String> answers = new ArrayList<>();
for (int i = 0; i < options.size(); i++) {
answers.add(selectedChoiceIndexes.contains(i) ? "1" : "0");
}
return answers.stream().collect(Collectors.joining(","));
}
private String migrateChoice(final List<Integer> selectedChoiceIndexes, final GridImageContent.Grid grid) {
return selectedChoiceIndexes.stream()
.map(i -> {
final int x = i % grid.getColumns();
final int y = i / grid.getColumns();
return x + ";" + y;
})
.collect(Collectors.joining(","));
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,116 +15,204 @@
* 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.entities;
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
public class Answer {
import de.thm.arsnova.model.serialization.View;
private String _id;
private String _rev;
/**
* Both a regular (single choice, evaluation, etc.) as well as a freetext answer.
*
* <p>
* This class has additional fields to transport generated answer statistics.
* </p>
*/
@ApiModel(value = "Answer", description = "Answer entity - Can represent a single answer or summarized statistics")
public class Answer implements Entity {
private String id;
private String rev;
private String type;
private String sessionId;
private String questionId;
private String answerText;
private String answerTextRaw;
private String answerSubject;
private boolean successfulFreeTextAnswer;
private String questionVariant;
private int questionValue;
private int piRound;
private String user;
private long timestamp;
private boolean read;
private int answerCount = 1;
private boolean abstention;
private int abstentionCount;
@JsonIgnore
private String answerImage;
private String answerThumbnailImage;
public Answer() {
this.type = "skill_question_answer";
}
public final String get_id() {
return _id;
}
public final void set_id(String _id) {
this._id = _id;
}
public final String get_rev() {
return _rev;
@ApiModelProperty(required = true, value = "the couchDB ID")
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
public final void set_rev(final String _rev) {
this._rev = _rev;
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
public final String getType() {
return type;
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
public final void setType(final String type) {
this.type = type;
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
@ApiModelProperty(required = true, value = "ID of the session, the answer is assigned to")
@JsonView({View.Persistence.class, View.Public.class})
public final String getSessionId() {
return sessionId;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setSessionId(final String sessionId) {
this.sessionId = sessionId;
}
@ApiModelProperty(required = true, value = "used to display question id")
@JsonView({View.Persistence.class, View.Public.class})
public final String getQuestionId() {
return questionId;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setQuestionId(final String questionId) {
this.questionId = questionId;
}
@ApiModelProperty(required = true, value = "the answer text")
@JsonView({View.Persistence.class, View.Public.class})
public final String getAnswerText() {
return answerText;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setAnswerText(final String answerText) {
this.answerText = answerText;
}
@JsonView({View.Persistence.class, View.Public.class})
public final String getAnswerTextRaw() {
return this.answerTextRaw;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setAnswerTextRaw(final String answerTextRaw) {
this.answerTextRaw = answerTextRaw;
}
@ApiModelProperty(required = true, value = "the answer subject")
@JsonView({View.Persistence.class, View.Public.class})
public final String getAnswerSubject() {
return answerSubject;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setAnswerSubject(final String answerSubject) {
this.answerSubject = answerSubject;
}
@JsonView({View.Persistence.class, View.Public.class})
public final boolean isSuccessfulFreeTextAnswer() {
return this.successfulFreeTextAnswer;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setSuccessfulFreeTextAnswer(final boolean successfulFreeTextAnswer) {
this.successfulFreeTextAnswer = successfulFreeTextAnswer;
}
@ApiModelProperty(required = true, value = "the peer instruction round nr.")
@JsonView({View.Persistence.class, View.Public.class})
public int getPiRound() {
return piRound;
}
public void setPiRound(int piRound) {
@JsonView({View.Persistence.class, View.Public.class})
public void setPiRound(final int piRound) {
this.piRound = piRound;
}
/* TODO: use JsonViews instead of JsonIgnore when supported by Spring (4.1)
* http://wiki.fasterxml.com/JacksonJsonViews
* https://jira.spring.io/browse/SPR-7156 */
@JsonIgnore
@ApiModelProperty(required = true, value = "the user")
@JsonView(View.Persistence.class)
public final String getUser() {
return user;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setUser(final String user) {
this.user = user;
}
@ApiModelProperty(required = true, value = "the answer image")
@JsonView(View.Persistence.class)
public String getAnswerImage() {
return answerImage;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setAnswerImage(final String answerImage) {
this.answerImage = answerImage;
}
@ApiModelProperty(required = true, value = "the answer thumbnail")
@JsonView({View.Persistence.class, View.Public.class})
public String getAnswerThumbnailImage() {
return answerThumbnailImage;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setAnswerThumbnailImage(final String answerThumbnailImage) {
this.answerThumbnailImage = answerThumbnailImage;
}
@ApiModelProperty(required = true, value = "the creation date timestamp")
@JsonView({View.Persistence.class, View.Public.class})
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
@JsonView(View.Persistence.class)
public void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
@ApiModelProperty(required = true, value = "displays whether the answer is read")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isRead() {
return read;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setRead(final boolean read) {
this.read = read;
}
@ApiModelProperty(required = true, value = "the number of answers given. used for statistics")
@JsonView(View.Public.class)
public final int getAnswerCount() {
return answerCount;
}
......@@ -133,35 +221,46 @@ public class Answer {
this.answerCount = answerCount;
}
@ApiModelProperty(required = true, value = "the abstention")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isAbstention() {
return abstention;
}
public void setAbstention(boolean abstention) {
@JsonView({View.Persistence.class, View.Public.class})
public void setAbstention(final boolean abstention) {
this.abstention = abstention;
}
@ApiModelProperty(required = true, value = "the number of abstentions given. used for statistics")
@JsonView(View.Public.class)
public int getAbstentionCount() {
return abstentionCount;
}
public void setAbstentionCount(int abstentionCount) {
public void setAbstentionCount(final int abstentionCount) {
this.abstentionCount = abstentionCount;
}
@ApiModelProperty(required = true, value = "either lecture or preparation")
@JsonView({View.Persistence.class, View.Public.class})
public String getQuestionVariant() {
return questionVariant;
}
public void setQuestionVariant(String questionVariant) {
@JsonView({View.Persistence.class, View.Public.class})
public void setQuestionVariant(final String questionVariant) {
this.questionVariant = questionVariant;
}
@ApiModelProperty(required = true, value = "used to display question value")
@JsonView({View.Persistence.class, View.Public.class})
public int getQuestionValue() {
return questionValue;
}
public void setQuestionValue(int questionValue) {
@JsonView({View.Persistence.class, View.Public.class})
public void setQuestionValue(final int questionValue) {
this.questionValue = questionValue;
}
......@@ -181,8 +280,8 @@ public class Answer {
// auto generated!
final int prime = 31;
int result = 1;
result = prime * result + ((_id == null) ? 0 : _id.hashCode());
result = prime * result + ((_rev == null) ? 0 : _rev.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((rev == null) ? 0 : rev.hashCode());
result = prime * result + ((answerSubject == null) ? 0 : answerSubject.hashCode());
result = prime * result + ((answerText == null) ? 0 : answerText.hashCode());
result = prime * result + piRound;
......@@ -194,26 +293,30 @@ public class Answer {
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
// auto generated!
if (this == obj) return true;
if (obj == null) return false;
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Answer other = (Answer) obj;
if (_id == null) {
if (other._id != null) {
final Answer other = (Answer) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!_id.equals(other._id)) {
} else if (!id.equals(other.id)) {
return false;
}
if (_rev == null) {
if (other._rev != null) {
if (rev == null) {
if (other.rev != null) {
return false;
}
} else if (!_rev.equals(other._rev)) {
} else if (!rev.equals(other.rev)) {
return false;
}
if (answerSubject == null) {
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import de.thm.arsnova.model.serialization.View;
/**
* Represents an Answer (Possible Answer) of Content.
*/
@ApiModel(value = "AnswerOption", description = "Answer Option (Possible Answer) entity")
public class AnswerOption implements Serializable {
private String id;
private String text;
private boolean correct;
private int value;
@ApiModelProperty(required = true, value = "the ID")
public String getId() {
return this.id;
}
public void setId(final String id) {
this.id = id;
}
@ApiModelProperty(required = true, value = "the text")
@JsonView({View.Persistence.class, View.Public.class})
public String getText() {
return text;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setText(final String text) {
this.text = text;
}
@ApiModelProperty(required = true, value = "true for a correct answer")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isCorrect() {
return correct;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setCorrect(final boolean correct) {
this.correct = correct;
}
@ApiModelProperty(required = true, value = "the value")
@JsonView({View.Persistence.class, View.Public.class})
public int getValue() {
return value;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setValue(final int value) {
this.value = value;
}
@Override
public String toString() {
return "AnswerOption [id=" + id + ", text=" + text + ", correct=" + correct + "]";
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,95 +15,96 @@
* 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.entities;
import java.io.Serializable;
package de.thm.arsnova.model.migration.v2;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.scribe.up.profile.facebook.FacebookProfile;
import org.scribe.up.profile.google.Google2Profile;
import org.scribe.up.profile.twitter.TwitterProfile;
import com.fasterxml.jackson.annotation.JsonView;
import java.io.Serializable;
import java.util.Objects;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import de.thm.arsnova.services.UserSessionService;
import de.thm.arsnova.model.UserProfile;
import de.thm.arsnova.model.serialization.View;
import de.thm.arsnova.security.User;
public class User implements Serializable {
public static final String GOOGLE = "google";
public static final String TWITTER = "twitter";
public static final String FACEBOOK = "facebook";
public static final String THM = "thm";
public static final String LDAP = "ldap";
public static final String ARSNOVA = "arsnova";
/**
* Represents a user.
*/
public class ClientAuthentication implements Serializable {
public static final String ANONYMOUS = "anonymous";
public static final String GUEST = "guest";
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String type;
private UserSessionService.Role role;
public User(Google2Profile profile) {
setUsername(profile.getEmail());
setType(User.GOOGLE);
}
public User(TwitterProfile profile) {
setUsername(profile.getScreenName());
setType(User.TWITTER);
}
public User(FacebookProfile profile) {
setUsername(profile.getLink());
setType(User.FACEBOOK);
}
public User(AttributePrincipal principal) {
setUsername(principal.getName());
setType(User.THM);
private UserProfile.AuthProvider authProvider;
private boolean isAdmin;
public ClientAuthentication() {
username = ANONYMOUS;
authProvider = UserProfile.AuthProvider.NONE;
}
public ClientAuthentication(final User user) {
id = user.getId();
username = user.getUsername();
authProvider = user.getAuthProvider();
isAdmin = user.isAdmin();
}
public ClientAuthentication(final Authentication authentication) {
if (authentication instanceof AnonymousAuthenticationToken) {
setUsername(ClientAuthentication.ANONYMOUS);
} else {
if (!(authentication.getPrincipal() instanceof User)) {
throw new IllegalArgumentException("Unsupported authentication token");
}
final User user = (User) authentication.getPrincipal();
id = user.getId();
username = user.getUsername();
authProvider = user.getAuthProvider();
isAdmin = user.isAdmin();
}
}
public User(AnonymousAuthenticationToken token) {
setUsername(User.ANONYMOUS);
setType(User.ANONYMOUS);
public String getId() {
return id;
}
public User(UsernamePasswordAuthenticationToken token) {
setUsername(token.getName());
setType(LDAP);
public void setId(final String id) {
this.id = id;
}
@JsonView(View.Public.class)
public String getUsername() {
return username;
}
public void setUsername(String username) {
public void setUsername(final String username) {
this.username = username;
}
public String getType() {
return type;
@JsonView(View.Public.class)
public UserProfile.AuthProvider getAuthProvider() {
return authProvider;
}
public void setType(String type) {
this.type = type;
public void setAuthProvider(final UserProfile.AuthProvider authProvider) {
this.authProvider = authProvider;
}
public UserSessionService.Role getRole() {
return role;
public void setAdmin(final boolean a) {
this.isAdmin = a;
}
public void setRole(UserSessionService.Role role) {
this.role = role;
}
public boolean hasRole(UserSessionService.Role role) {
return this.role == role;
@JsonView(View.Public.class)
public boolean isAdmin() {
return this.isAdmin;
}
@Override
public String toString() {
return "User [username=" + username + ", type=" + type + "]";
return "User [username=" + username + ", authProvider=" + authProvider + "]";
}
@Override
......@@ -114,16 +115,18 @@ public class User implements Serializable {
int result = theAnswer;
result = theOthers * result + this.username.hashCode();
return theOthers * result + this.type.hashCode();
return theOthers * result + this.authProvider.hashCode();
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
User other = (User) obj;
return this.username.equals(other.username) && this.type.equals(other.type);
final ClientAuthentication other = (ClientAuthentication) obj;
return this.authProvider == other.authProvider
&& Objects.equals(this.id, other.id) && this.username.equals(other.username);
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,15 +15,23 @@
* 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.entities;
import com.fasterxml.jackson.annotation.JsonIgnore;
package de.thm.arsnova.model.migration.v2;
public class InterposedQuestion {
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
private String _id;
private String _rev;
private String type;
import de.thm.arsnova.model.serialization.View;
/**
* A Comment (Interposed/Feedback/Audience question) from a attendee in a Room.
*/
@ApiModel(value = "Comment", description = "Comment (Interposed/Feedback/Audience Question) entity")
public class Comment implements Entity {
private String id;
private String rev;
private String subject;
private String text;
/* FIXME sessionId actually is used to hold the sessionKey.
......@@ -36,68 +44,100 @@ public class InterposedQuestion {
private boolean read;
private String creator;
public String get_id() {
return _id;
@JsonView({View.Persistence.class, View.Public.class})
@JsonProperty("_id")
public String getId() {
return id;
}
public void set_id(String _id) {
this._id = _id;
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
public String get_rev() {
return _rev;
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
public void set_rev(String _rev) {
this._rev = _rev;
/* Need because of an inconsistency in the v2 API */
@JsonView(View.Public.class)
@JsonProperty("id")
public String getApiId() {
return id;
}
@ApiModelProperty(required = true, value = "is read")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isRead() {
return read;
}
public void setRead(boolean read) {
@JsonView({View.Persistence.class, View.Public.class})
public void setRead(final boolean read) {
this.read = read;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@ApiModelProperty(required = true, value = "the subject")
@JsonView({View.Persistence.class, View.Public.class})
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
@JsonView({View.Persistence.class, View.Public.class})
public void setSubject(final String subject) {
this.subject = subject;
}
@ApiModelProperty(required = true, value = "the Text")
@JsonView({View.Persistence.class, View.Public.class})
public String getText() {
return text;
}
public void setText(String text) {
@JsonView({View.Persistence.class, View.Public.class})
public void setText(final String text) {
this.text = text;
}
@ApiModelProperty(required = true, value = "ID of the session, the comment is assigned to")
@JsonView(View.Persistence.class)
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
@JsonView({View.Persistence.class, View.Public.class})
public void setSessionId(final String sessionId) {
this.sessionId = sessionId;
}
@ApiModelProperty(required = true, value = "creation date timestamp")
@JsonView({View.Persistence.class, View.Public.class})
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
@JsonView({View.Persistence.class, View.Public.class})
public void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
/* TODO: use JsonViews instead of JsonIgnore when supported by Spring (4.1)
* http://wiki.fasterxml.com/JacksonJsonViews
* https://jira.spring.io/browse/SPR-7156 */
@JsonIgnore
@JsonView(View.Persistence.class)
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
@JsonView(View.Persistence.class)
public void setCreator(final String creator) {
this.creator = creator;
}
public boolean isCreator(User user) {
public boolean isCreator(final ClientAuthentication user) {
return user.getUsername().equals(creator);
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import de.thm.arsnova.model.serialization.View;
/**
* Wrapper class for counting read and unread Comments for a Room or a single user.
*/
@ApiModel(value = "Comment Reading Count", description = "Comment Reading Count statistics entity")
public class CommentReadingCount {
private int read;
private int unread;
public CommentReadingCount(final int readCount, final int unreadCount) {
this.read = readCount;
this.unread = unreadCount;
}
public CommentReadingCount() {
this.read = 0;
this.unread = 0;
}
@ApiModelProperty(required = true, value = "the number of read comments")
@JsonView(View.Public.class)
public int getRead() {
return read;
}
public void setRead(final int read) {
this.read = read;
}
@ApiModelProperty(required = true, value = "the number of unread comments")
@JsonView(View.Public.class)
public int getUnread() {
return unread;
}
public void setUnread(final int unread) {
this.unread = unread;
}
@ApiModelProperty(required = true, value = "the number of total comments")
@JsonView(View.Public.class)
public int getTotal() {
return getRead() + getUnread();
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,21 +15,32 @@
* 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.entities;
import java.util.HashMap;
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Question {
import de.thm.arsnova.model.serialization.View;
private String type;
/**
* Represents Content (Skill/Lecturer Question) in a Room.
*/
@ApiModel(value = "Content", description = "Content (Skill/Lecturer Question) entity")
public class Content implements Entity {
private String id;
private String rev;
private String questionType;
private String questionVariant;
private String subject;
private String text;
private boolean active;
private String releasedFor;
private List<PossibleAnswer> possibleAnswers;
private List<AnswerOption> possibleAnswers;
private boolean noCorrect;
// TODO: We currently need both sessionId and sessionKeyword, but sessionKeyword will not be persisted.
private String sessionId;
......@@ -39,14 +50,21 @@ public class Question {
private int number;
private int duration;
private int piRound;
private long piRoundEndTime;
private long piRoundStartTime;
private boolean piRoundActive;
private long piRoundEndTime = 0;
private long piRoundStartTime = 0;
private boolean piRoundFinished = false;
private boolean piRoundActive = false;
private boolean votingDisabled;
private boolean showStatistic; // sic
private boolean showAnswer;
private boolean abstention;
private String _id;
private String _rev;
private boolean ignoreCaseSensitive;
private boolean ignoreWhitespaces;
private boolean ignorePunctuation;
private boolean fixedAnswer;
private boolean strictMode;
private int rating;
private String correctAnswer;
private String image;
private String fcImage;
......@@ -70,55 +88,88 @@ public class Question {
private String gridType;
private String scaleFactor;
private String gridScaleFactor;
private boolean imageQuestion;
private boolean textAnswerEnabled;
private String hint;
private String solution;
@ApiModelProperty(required = true, value = "the couchDB ID")
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
public final String getType() {
return type;
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
public final void setType(final String type) {
this.type = type;
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
@ApiModelProperty(required = true, value = "the question type")
@JsonView({View.Persistence.class, View.Public.class})
public final String getQuestionType() {
return questionType;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setQuestionType(final String questionType) {
this.questionType = questionType;
}
@ApiModelProperty(required = true, value = "either lecture or preparation")
@JsonView({View.Persistence.class, View.Public.class})
public final String getQuestionVariant() {
return questionVariant;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setQuestionVariant(final String questionVariant) {
this.questionVariant = questionVariant;
}
@ApiModelProperty(required = true, value = "used to display subject")
@JsonView({View.Persistence.class, View.Public.class})
public final String getSubject() {
return subject;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setSubject(final String subject) {
this.subject = subject;
}
@ApiModelProperty(required = true, value = "the text")
@JsonView({View.Persistence.class, View.Public.class})
public final String getText() {
return text;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setText(final String text) {
this.text = text;
}
@ApiModelProperty(required = true, value = "true for active question")
@JsonView({View.Persistence.class, View.Public.class})
public final boolean isActive() {
return active;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setActive(final boolean active) {
this.active = active;
}
@ApiModelProperty(required = true, value = "deprecated - previously used to limitate the audience")
public final String getReleasedFor() {
return releasedFor;
}
......@@ -127,14 +178,18 @@ public class Question {
this.releasedFor = releasedFor;
}
public final List<PossibleAnswer> getPossibleAnswers() {
return possibleAnswers;
@ApiModelProperty(required = true, value = "list of possible answers")
@JsonView({View.Persistence.class, View.Public.class})
public final List<AnswerOption> getPossibleAnswers() {
return possibleAnswers != null ? possibleAnswers : new ArrayList<>();
}
public final void setPossibleAnswers(final List<PossibleAnswer> possibleAnswers) {
@JsonView({View.Persistence.class, View.Public.class})
public final void setPossibleAnswers(final List<AnswerOption> possibleAnswers) {
this.possibleAnswers = possibleAnswers;
}
@ApiModelProperty(required = true, value = "if true, no answer is marked correct")
public final boolean isNoCorrect() {
return noCorrect;
}
......@@ -143,14 +198,18 @@ public class Question {
this.noCorrect = noCorrect;
}
@ApiModelProperty(required = true, value = "couchDB ID of the session, the question is assigned to")
@JsonView({View.Persistence.class, View.Public.class})
public final String getSessionId() {
return sessionId;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setSessionId(final String sessionId) {
this.sessionId = sessionId;
}
@ApiModelProperty(required = true, value = "couchDB ID of the session, the question is assigned to")
public final String getSession() {
return sessionId;
}
......@@ -159,22 +218,28 @@ public class Question {
sessionId = session;
}
@ApiModelProperty(required = true, value = "the room keyword, the question is assigned to")
public final String getSessionKeyword() {
return sessionKeyword;
}
//@JsonView(View.Public.class)
public final void setSessionKeyword(final String keyword) {
sessionKeyword = keyword;
}
@ApiModelProperty(required = true, value = "creation date timestamp")
@JsonView(View.Persistence.class)
public final long getTimestamp() {
return timestamp;
}
@JsonView(View.Persistence.class)
public final void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
@ApiModelProperty(required = true, value = "used to display number")
public final int getNumber() {
return number;
}
......@@ -183,265 +248,469 @@ public class Question {
this.number = number;
}
@ApiModelProperty(required = true, value = "used to display duration")
@JsonView({View.Persistence.class, View.Public.class})
public final int getDuration() {
return duration;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setDuration(final int duration) {
this.duration = duration;
}
@ApiModelProperty(required = true, value = "true for image question")
@JsonView({View.Persistence.class, View.Public.class})
public final boolean isImageQuestion() {
return imageQuestion;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setImageQuestion(final boolean imageQuestion) {
this.imageQuestion = imageQuestion;
}
@ApiModelProperty(required = true, value = "the peer instruction round no.")
@JsonView({View.Persistence.class, View.Public.class})
public int getPiRound() {
return piRound;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPiRound(final int piRound) {
this.piRound = piRound;
}
@ApiModelProperty(required = true, value = "the peer instruction round end timestamp")
@JsonView({View.Persistence.class, View.Public.class})
public long getPiRoundEndTime() {
return piRoundEndTime;
}
public void setPiRoundEndTime(long piRoundEndTime) {
@JsonView({View.Persistence.class, View.Public.class})
public void setPiRoundEndTime(final long piRoundEndTime) {
this.piRoundEndTime = piRoundEndTime;
}
@ApiModelProperty(required = true, value = "the peer instruction round start timestamp")
@JsonView({View.Persistence.class, View.Public.class})
public long getPiRoundStartTime() {
return piRoundStartTime;
}
public void setPiRoundStartTime(long piRoundStartTime) {
@JsonView({View.Persistence.class, View.Public.class})
public void setPiRoundStartTime(final long piRoundStartTime) {
this.piRoundStartTime = piRoundStartTime;
}
@ApiModelProperty(required = true, value = "true for active peer instruction round")
public boolean isPiRoundActive() {
return piRoundActive;
}
public void setPiRoundActive(boolean piRoundActive) {
public void setPiRoundActive(final boolean piRoundActive) {
this.piRoundActive = piRoundActive;
}
@ApiModelProperty(required = true, value = "true for finished peer instruction round")
public boolean isPiRoundFinished() {
return piRoundFinished;
}
public void setPiRoundFinished(final boolean piRoundFinished) {
this.piRoundFinished = piRoundFinished;
}
@ApiModelProperty(required = true, value = "used to display showStatistic")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isShowStatistic() {
return showStatistic;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setShowStatistic(final boolean showStatistic) {
this.showStatistic = showStatistic;
}
@ApiModelProperty(required = true, value = "used to display cvIsColored")
@JsonView({View.Persistence.class, View.Public.class})
public boolean getCvIsColored() {
return cvIsColored;
}
public void setCvIsColored(boolean cvIsColored) {
@JsonView({View.Persistence.class, View.Public.class})
public void setCvIsColored(final boolean cvIsColored) {
this.cvIsColored = cvIsColored;
}
@ApiModelProperty(required = true, value = "used to display showAnswer")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isShowAnswer() {
return showAnswer;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setShowAnswer(final boolean showAnswer) {
this.showAnswer = showAnswer;
}
@ApiModelProperty(required = true, value = "used to display abstention")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isAbstention() {
return abstention;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setAbstention(final boolean abstention) {
this.abstention = abstention;
}
public final String get_id() {
return _id;
@JsonView({View.Persistence.class, View.Public.class})
public boolean isIgnoreCaseSensitive() {
return ignoreCaseSensitive;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setIgnoreCaseSensitive(final boolean ignoreCaseSensitive) {
this.ignoreCaseSensitive = ignoreCaseSensitive;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isIgnoreWhitespaces() {
return ignoreWhitespaces;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setIgnoreWhitespaces(final boolean ignoreWhitespaces) {
this.ignoreWhitespaces = ignoreWhitespaces;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isIgnorePunctuation() {
return ignorePunctuation;
}
public final void set_id(final String _id) {
this._id = _id;
@JsonView({View.Persistence.class, View.Public.class})
public void setIgnorePunctuation(final boolean ignorePunctuation) {
this.ignorePunctuation = ignorePunctuation;
}
public final String get_rev() {
return _rev;
@JsonView({View.Persistence.class, View.Public.class})
public boolean isFixedAnswer() {
return this.fixedAnswer;
}
public final void set_rev(final String _rev) {
this._rev = _rev;
@JsonView({View.Persistence.class, View.Public.class})
public void setFixedAnswer(final boolean fixedAnswer) {
this.fixedAnswer = fixedAnswer;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isStrictMode() {
return this.strictMode;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setStrictMode(final boolean strictMode) {
this.strictMode = strictMode;
}
@JsonView({View.Persistence.class, View.Public.class})
public final int getRating() {
return this.rating;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setRating(final int rating) {
this.rating = rating;
}
@JsonView({View.Persistence.class, View.Public.class})
public final String getCorrectAnswer() {
return correctAnswer;
}
@JsonView({View.Persistence.class, View.Public.class})
public final void setCorrectAnswer(final String correctAnswer) {
this.correctAnswer = correctAnswer;
}
@ApiModelProperty(required = true, value = "the image")
@JsonView({View.Persistence.class, View.Public.class})
public String getImage() {
return image;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setImage(final String image) {
this.image = image;
}
@ApiModelProperty(required = true, value = "the fcImage")
@JsonView({View.Persistence.class, View.Public.class})
public String getFcImage() {
return fcImage;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFcImage(final String fcImage) {
this.fcImage = fcImage;
}
@ApiModelProperty(required = true, value = "the grid size")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridSize() {
return gridSize;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setGridSize(final int gridSize) {
this.gridSize = gridSize;
}
@ApiModelProperty(required = true, value = "the image X offset")
@JsonView({View.Persistence.class, View.Public.class})
public int getOffsetX() {
return offsetX;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setOffsetX(final int offsetX) {
this.offsetX = offsetX;
}
@ApiModelProperty(required = true, value = "the image Y offset")
@JsonView({View.Persistence.class, View.Public.class})
public int getOffsetY() {
return offsetY;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setOffsetY(final int offsetY) {
this.offsetY = offsetY;
}
@ApiModelProperty(required = true, value = "the image zoom level")
@JsonView({View.Persistence.class, View.Public.class})
public int getZoomLvl() {
return zoomLvl;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setZoomLvl(final int zoomLvl) {
this.zoomLvl = zoomLvl;
}
@ApiModelProperty(required = true, value = "the grid X offset")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridOffsetX() {
return gridOffsetX;
}
public void setGridOffsetX(int gridOffsetX) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridOffsetX(final int gridOffsetX) {
this.gridOffsetX = gridOffsetX;
}
@ApiModelProperty(required = true, value = "the grid Y offset")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridOffsetY() {
return gridOffsetY;
}
public void setGridOffsetY(int gridOffsetY) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridOffsetY(final int gridOffsetY) {
this.gridOffsetY = gridOffsetY;
}
@ApiModelProperty(required = true, value = "the grid zoom lvl")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridZoomLvl() {
return gridZoomLvl;
}
public void setGridZoomLvl(int gridZoomLvl) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridZoomLvl(final int gridZoomLvl) {
this.gridZoomLvl = gridZoomLvl;
}
@ApiModelProperty(required = true, value = "the grid X size")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridSizeX() {
return gridSizeX;
}
public void setGridSizeX(int gridSizeX) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridSizeX(final int gridSizeX) {
this.gridSizeX = gridSizeX;
}
@ApiModelProperty(required = true, value = "the grid Y size")
@JsonView({View.Persistence.class, View.Public.class})
public int getGridSizeY() {
return gridSizeY;
}
public void setGridSizeY(int gridSizeY) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridSizeY(final int gridSizeY) {
this.gridSizeY = gridSizeY;
}
@ApiModelProperty(required = true, value = "true for hidden grid")
@JsonView({View.Persistence.class, View.Public.class})
public boolean getGridIsHidden() {
return gridIsHidden;
}
public void setGridIsHidden(boolean gridIsHidden) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridIsHidden(final boolean gridIsHidden) {
this.gridIsHidden = gridIsHidden;
}
@ApiModelProperty(required = true, value = "the image rotation")
@JsonView({View.Persistence.class, View.Public.class})
public int getImgRotation() {
return imgRotation;
}
public void setImgRotation(int imgRotation) {
@JsonView({View.Persistence.class, View.Public.class})
public void setImgRotation(final int imgRotation) {
this.imgRotation = imgRotation;
}
@ApiModelProperty(required = true, value = "the toggled left fields")
@JsonView({View.Persistence.class, View.Public.class})
public boolean getToggleFieldsLeft() {
return toggleFieldsLeft;
}
public void setToggleFieldsLeft(boolean toggleFieldsLeft) {
@JsonView({View.Persistence.class, View.Public.class})
public void setToggleFieldsLeft(final boolean toggleFieldsLeft) {
this.toggleFieldsLeft = toggleFieldsLeft;
}
@ApiModelProperty(required = true, value = "the number of clickable fields")
@JsonView({View.Persistence.class, View.Public.class})
public int getNumClickableFields() {
return numClickableFields;
}
public void setNumClickableFields(int numClickableFields) {
@JsonView({View.Persistence.class, View.Public.class})
public void setNumClickableFields(final int numClickableFields) {
this.numClickableFields = numClickableFields;
}
@ApiModelProperty(required = true, value = "the threshold of correct answers")
@JsonView({View.Persistence.class, View.Public.class})
public int getThresholdCorrectAnswers() {
return thresholdCorrectAnswers;
}
public void setThresholdCorrectAnswers(int thresholdCorrectAnswers) {
@JsonView({View.Persistence.class, View.Public.class})
public void setThresholdCorrectAnswers(final int thresholdCorrectAnswers) {
this.thresholdCorrectAnswers = thresholdCorrectAnswers;
}
@ApiModelProperty(required = true, value = "the grid line color")
@JsonView({View.Persistence.class, View.Public.class})
public String getGridLineColor() {
return gridLineColor;
}
public void setGridLineColor(String gridLineColor) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridLineColor(final String gridLineColor) {
this.gridLineColor = gridLineColor;
}
@ApiModelProperty(required = true, value = "the number of dots")
@JsonView({View.Persistence.class, View.Public.class})
public int getNumberOfDots() {
return numberOfDots;
}
public void setNumberOfDots(int numberOfDots) {
@JsonView({View.Persistence.class, View.Public.class})
public void setNumberOfDots(final int numberOfDots) {
this.numberOfDots = numberOfDots;
}
@ApiModelProperty(required = true, value = "the grid type")
@JsonView({View.Persistence.class, View.Public.class})
public String getGridType() {
return gridType;
}
public void setGridType(String gridType) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridType(final String gridType) {
this.gridType = gridType;
}
public void setScaleFactor(String scaleFactor) {
@JsonView({View.Persistence.class, View.Public.class})
public void setScaleFactor(final String scaleFactor) {
this.scaleFactor = scaleFactor;
}
@ApiModelProperty(required = true, value = "the image scale factor")
@JsonView({View.Persistence.class, View.Public.class})
public String getScaleFactor() {
return this.scaleFactor;
}
public void setGridScaleFactor(String scaleFactor) {
@JsonView({View.Persistence.class, View.Public.class})
public void setGridScaleFactor(final String scaleFactor) {
this.gridScaleFactor = scaleFactor;
}
@ApiModelProperty(required = true, value = "the grid scale factor")
@JsonView({View.Persistence.class, View.Public.class})
public String getGridScaleFactor() {
return this.gridScaleFactor;
}
@ApiModelProperty(required = true, value = "true for a question that can be answered via text")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isTextAnswerEnabled() {
return this.textAnswerEnabled;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setTextAnswerEnabled(final boolean textAnswerEnabled) {
this.textAnswerEnabled = textAnswerEnabled;
}
@ApiModelProperty(required = true, value = "true for disabled voting")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isVotingDisabled() {
return votingDisabled;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setVotingDisabled(final boolean votingDisabled) {
this.votingDisabled = votingDisabled;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getHint() {
return hint;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setHint(final String hint) {
this.hint = hint;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getSolution() {
return solution;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setSolution(final String solution) {
this.solution = solution;
}
@Override
public final String toString() {
return "Question type '" + type + "': " + subject + ";\n" + text + possibleAnswers;
return "Content type '" + questionType + "': " + subject + ";\n" + text + possibleAnswers;
}
@Override
......@@ -449,52 +718,141 @@ public class Question {
// auto generated!
final int prime = 31;
int result = 1;
result = prime * result + ((_id == null) ? 0 : _id.hashCode());
result = prime * result + ((_rev == null) ? 0 : _rev.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
// auto generated!
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
Question other = (Question) obj;
if (_id == null) {
if (other._id != null) {
return false;
}
} else if (!_id.equals(other._id)) {
if (getClass() != obj.getClass()) {
return false;
}
if (_rev == null) {
if (other._rev != null) {
final Content other = (Content) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!_rev.equals(other._rev)) {
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
public int calculateValue(Answer answer) {
public int calculateValue(final Answer answer) {
if (answer.isAbstention()) {
return 0;
} else if (this.questionType.equals("mc")) {
} else if ("mc".equals(this.questionType)) {
return calculateMultipleChoiceValue(answer);
} else if (this.questionType.equals("grid")) {
} else if ("grid".equals(this.questionType)) {
return calculateGridValue(answer);
} else {
return calculateRegularValue(answer);
}
}
private int calculateRegularValue(Answer answer) {
String answerText = answer.getAnswerText();
for (PossibleAnswer p : this.possibleAnswers) {
public String checkCaseSensitive(final String answerText) {
if (this.isIgnoreCaseSensitive()) {
this.setCorrectAnswer(this.getCorrectAnswer().toLowerCase());
return answerText.toLowerCase();
}
return answerText;
}
public String checkWhitespaces(final String answerText) {
if (this.isIgnoreWhitespaces()) {
this.setCorrectAnswer(this.getCorrectAnswer().replaceAll("[\\s]", ""));
return answerText.replaceAll("[\\s]", "");
}
return answerText;
}
public String checkPunctuation(final String answerText) {
if (this.isIgnorePunctuation()) {
this.setCorrectAnswer(this.getCorrectAnswer().replaceAll("\\p{Punct}", ""));
return answerText.replaceAll("\\p{Punct}", "");
}
return answerText;
}
public void checkTextStrictOptions(final Answer answer) {
answer.setAnswerTextRaw(this.checkCaseSensitive(answer.getAnswerTextRaw()));
answer.setAnswerTextRaw(this.checkPunctuation(answer.getAnswerTextRaw()));
answer.setAnswerTextRaw(this.checkWhitespaces(answer.getAnswerTextRaw()));
}
public int evaluateCorrectAnswerFixedText(final String answerTextRaw) {
if (answerTextRaw != null) {
if (answerTextRaw.equals(this.getCorrectAnswer())) {
return this.getRating();
}
}
return 0;
}
public boolean isSuccessfulFreeTextAnswer(final String answerTextRaw) {
return answerTextRaw != null && answerTextRaw.equals(this.getCorrectAnswer());
}
public void updateRoundStartVariables(final Date start, final Date end) {
if (this.getPiRound() == 1 && this.isPiRoundFinished()) {
this.setPiRound(2);
}
this.setActive(true);
this.setShowAnswer(false);
this.setPiRoundActive(true);
this.setShowStatistic(false);
this.setVotingDisabled(false);
this.setPiRoundFinished(false);
this.setPiRoundStartTime(start.getTime());
this.setPiRoundEndTime(end.getTime());
}
public void updateRoundManagementState() {
final long time = new Date().getTime();
if (time > this.getPiRoundEndTime() && this.isPiRoundActive()) {
this.setPiRoundEndTime(0);
this.setPiRoundStartTime(0);
this.setPiRoundActive(false);
this.setPiRoundFinished(true);
}
}
public void resetRoundManagementState() {
this.setPiRoundEndTime(0);
this.setPiRoundStartTime(0);
this.setVotingDisabled(true);
this.setPiRoundActive(false);
this.setPiRoundFinished(false);
this.setShowStatistic(false);
this.setShowAnswer(false);
}
public void resetQuestionState() {
this.setPiRoundEndTime(0);
this.setPiRoundStartTime(0);
this.setPiRoundActive(false);
this.setPiRoundFinished(false);
this.setVotingDisabled(false);
if ("freetext".equals(this.getQuestionType())) {
this.setPiRound(0);
} else {
this.setPiRound(1);
}
}
private int calculateRegularValue(final Answer answer) {
final String answerText = answer.getAnswerText();
for (final AnswerOption p : this.possibleAnswers) {
if (answerText.equals(p.getText())) {
return p.getValue();
}
......@@ -502,12 +860,12 @@ public class Question {
return 0;
}
private int calculateGridValue(Answer answer) {
private int calculateGridValue(final Answer answer) {
int value = 0;
String[] answers = answer.getAnswerText().split(",");
for (int i = 0; i < answers.length; i++) {
for (PossibleAnswer p : this.possibleAnswers) {
if (answers[i].equals(p.getText())) {
final String[] answers = answer.getAnswerText().split(",");
for (final String a : answers) {
for (final AnswerOption p : this.possibleAnswers) {
if (a.equals(p.getText())) {
value += p.getValue();
}
}
......@@ -515,12 +873,12 @@ public class Question {
return value;
}
private int calculateMultipleChoiceValue(Answer answer) {
private int calculateMultipleChoiceValue(final Answer answer) {
int value = 0;
String[] answers = answer.getAnswerText().split(",");
final String[] answers = answer.getAnswerText().split(",");
for (int i = 0; i < this.possibleAnswers.size() && i < answers.length; i++) {
if (answers[i].equals("1")) {
PossibleAnswer p = this.possibleAnswers.get(i);
if ("1".equals(answers[i])) {
final AnswerOption p = this.possibleAnswers.get(i);
value += p.getValue();
}
}
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,9 +15,17 @@
* 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.entities;
public class DbUser {
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import de.thm.arsnova.model.serialization.View;
/**
* A user account for ARSnova's own registration and login process.
*/
public class DbUser implements Entity {
private String id;
private String rev;
private String username;
......@@ -28,90 +36,93 @@ public class DbUser {
private long creation;
private long lastLogin;
@JsonView(View.Persistence.class)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/* CouchDB deserialization */
public void set_id(String id) {
@JsonView(View.Persistence.class)
public void setId(final String id) {
this.id = id;
}
public String getRev() {
@JsonView(View.Persistence.class)
public String getRevision() {
return rev;
}
public void setRev(String rev) {
this.rev = rev;
}
/* CouchDB deserialization */
public void set_rev(String rev) {
@JsonView(View.Persistence.class)
public void setRevision(final String rev) {
this.rev = rev;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getUsername() {
return username;
}
public void setUsername(String username) {
@JsonView({View.Persistence.class, View.Public.class})
public void setUsername(final String username) {
this.username = username;
}
@JsonView(View.Persistence.class)
public String getPassword() {
return password;
}
public void setPassword(String password) {
@JsonView(View.Persistence.class)
public void setPassword(final String password) {
this.password = password;
}
@JsonView(View.Persistence.class)
public String getActivationKey() {
return activationKey;
}
public void setActivationKey(String activationKey) {
@JsonView(View.Persistence.class)
public void setActivationKey(final String activationKey) {
this.activationKey = activationKey;
}
@JsonView(View.Persistence.class)
public String getPasswordResetKey() {
return passwordResetKey;
}
public void setPasswordResetKey(String passwordResetKey) {
@JsonView(View.Persistence.class)
public void setPasswordResetKey(final String passwordResetKey) {
this.passwordResetKey = passwordResetKey;
}
@JsonView(View.Persistence.class)
public long getPasswordResetTime() {
return passwordResetTime;
}
public void setPasswordResetTime(long passwordResetTime) {
@JsonView(View.Persistence.class)
public void setPasswordResetTime(final long passwordResetTime) {
this.passwordResetTime = passwordResetTime;
}
@JsonView(View.Persistence.class)
public long getCreation() {
return creation;
}
public void setCreation(long creation) {
@JsonView(View.Persistence.class)
public void setCreation(final long creation) {
this.creation = creation;
}
@JsonView(View.Persistence.class)
public long getLastLogin() {
return lastLogin;
}
public void setLastLogin(long lastLogin) {
@JsonView(View.Persistence.class)
public void setLastLogin(final long lastLogin) {
this.lastLogin = lastLogin;
}
/* CouchDB deserialization */
public void setType(String type) {
/* no op */
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2017 The ARSnova Team
*
* 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
......@@ -15,21 +15,24 @@
* 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.events;
import de.thm.arsnova.entities.Session;
package de.thm.arsnova.model.migration.v2;
public class DeleteQuestionEvent extends SessionEvent {
import com.fasterxml.jackson.annotation.JsonView;
private static final long serialVersionUID = 1L;
import de.thm.arsnova.model.serialization.View;
public DeleteQuestionEvent(Object source, Session session) {
super(source, session);
}
public interface Entity {
String getId();
@Override
public void accept(NovaEventVisitor visitor) {
visitor.visit(this);
}
void setId(String id);
String getRevision();
void setRevision(String rev);
@JsonView(View.Persistence.class)
default Class<? extends Entity> getType() {
return getClass();
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import java.util.Map;
import de.thm.arsnova.model.serialization.View;
public class LogEntry implements Entity {
public enum LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL
}
private String id;
private String rev;
private long timestamp = System.currentTimeMillis();
private String event;
private int level;
private Map<String, Object> payload;
public LogEntry(@JsonProperty final String event, @JsonProperty final int level,
@JsonProperty final Map<String, Object> payload) {
this.event = event;
this.level = level;
this.payload = payload;
}
@JsonView(View.Persistence.class)
public String getId() {
return id;
}
@JsonView(View.Persistence.class)
public void setId(final String id) {
this.id = id;
}
@JsonView(View.Persistence.class)
public String getRevision() {
return rev;
}
@JsonView(View.Persistence.class)
public void setRevision(final String rev) {
this.rev = rev;
}
@JsonView(View.Persistence.class)
public long getTimestamp() {
return timestamp;
}
@JsonView(View.Persistence.class)
public void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
@JsonView(View.Persistence.class)
public String getEvent() {
return event;
}
@JsonView(View.Persistence.class)
public void setEvent(final String event) {
this.event = event;
}
@JsonView(View.Persistence.class)
public int getLevel() {
return level;
}
@JsonView(View.Persistence.class)
public void setLevel(final int level) {
this.level = level;
}
@JsonView(View.Persistence.class)
public void setLevel(final LogLevel level) {
this.level = level.ordinal();
}
@JsonView(View.Persistence.class)
public Map<String, Object> getPayload() {
return payload;
}
@JsonView(View.Persistence.class)
public void setPayload(final Map<String, Object> payload) {
this.payload = payload;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,117 +15,125 @@
* 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.entities;
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import java.util.ArrayList;
import java.util.List;
public class LoggedIn {
import de.thm.arsnova.model.serialization.View;
private String _id;
private String _rev;
private String type;
/**
* Once a user joins a session, this class is used to identify a returning user.
*/
@ApiModel(value = "LoggedIn", description = "Logged In entity - Contains the Room History (Visited Sessions)")
public class LoggedIn implements Entity {
private String id;
private String rev;
private String user;
private String sessionId;
private long timestamp;
private List<VisitedSession> visitedSessions = new ArrayList<VisitedSession>();
private List<String> _conflicts;
private List<VisitedRoom> visitedSessions = new ArrayList<>();
private boolean anonymized;
public LoggedIn() {
this.type = "logged_in";
this.updateTimestamp();
}
public void addVisitedSession(Session s) {
public void addVisitedSession(final Room s) {
if (!isAlreadyVisited(s)) {
this.visitedSessions.add(new VisitedSession(s));
this.visitedSessions.add(new VisitedRoom(s));
}
}
private boolean isAlreadyVisited(Session s) {
for (VisitedSession vs : this.visitedSessions) {
if (vs.get_id().equals(s.get_id())) {
private boolean isAlreadyVisited(final Room s) {
for (final VisitedRoom vs : this.visitedSessions) {
if (vs.getId().equals(s.getId())) {
return true;
}
}
return false;
}
public void updateTimestamp() {
this.timestamp = System.currentTimeMillis();
}
public String get_id() {
return _id;
@JsonView(View.Persistence.class)
public String getId() {
return id;
}
public void set_id(String _id) {
this._id = _id;
@JsonView(View.Persistence.class)
public void setId(final String id) {
this.id = id;
}
public String get_rev() {
return _rev;
@JsonView(View.Persistence.class)
public String getRevision() {
return rev;
}
public void set_rev(String _rev) {
this._rev = _rev;
@JsonView(View.Persistence.class)
public void setRevision(final String rev) {
this.rev = rev;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
public void updateTimestamp() {
this.timestamp = System.currentTimeMillis();
}
@JsonView(View.Persistence.class)
public String getUser() {
return user;
}
public void setUser(String user) {
@JsonView(View.Persistence.class)
public void setUser(final String user) {
this.user = user;
}
@JsonView(View.Persistence.class)
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
@JsonView(View.Persistence.class)
public void setSessionId(final String sessionId) {
this.sessionId = sessionId;
}
@JsonView(View.Persistence.class)
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
@JsonView(View.Persistence.class)
public void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
public List<VisitedSession> getVisitedSessions() {
@JsonView(View.Persistence.class)
public List<VisitedRoom> getVisitedSessions() {
return visitedSessions;
}
public void setVisitedSessions(List<VisitedSession> visitedSessions) {
@JsonView(View.Persistence.class)
public void setVisitedSessions(final List<VisitedRoom> visitedSessions) {
this.visitedSessions = visitedSessions;
}
public List<String> get_conflicts() {
return _conflicts;
}
public void set_conflicts(List<String> _conflicts) {
this._conflicts = _conflicts;
@JsonView(View.Persistence.class)
public boolean isAnonymized() {
return anonymized;
}
public boolean hasConflicts() {
return !(_conflicts == null || _conflicts.isEmpty());
@JsonView(View.Persistence.class)
public void setAnonymized(final boolean anonymized) {
this.anonymized = anonymized;
}
@Override
public String toString() {
return "LoggedIn [_id=" + _id + ", _rev=" + _rev + ", type=" + type
return "LoggedIn [id=" + id + ", rev=" + rev + ", type=" + getType()
+ ", user=" + user + ", sessionId=" + sessionId
+ ", timestamp=" + timestamp + ", visitedSessions="
+ visitedSessions + "]";
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import de.thm.arsnova.model.serialization.View;
/**
* Represents a Message of the Day.
*/
@ApiModel(value = "Motd", description = "Message of the Day entity")
public class Motd implements Entity {
private String motdkey; //ID
private Date startdate;
private Date enddate;
private String title;
private String text;
private String audience;
private String sessionId;
private String sessionkey;
private String id;
private String rev;
@ApiModelProperty(required = true, value = "the identification string")
@JsonView({View.Persistence.class, View.Public.class})
public String getMotdkey() {
return motdkey;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setMotdkey(final String key) {
motdkey = key;
}
@ApiModelProperty(required = true, value = "startdate for showing this message (timestamp format)")
@JsonView({View.Persistence.class, View.Public.class})
public Date getStartdate() {
return startdate;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setStartdate(final Date timestamp) {
startdate = timestamp;
}
@ApiModelProperty(required = true, value = "enddate for showing this message (timestamp format)")
@JsonView({View.Persistence.class, View.Public.class})
public Date getEnddate() {
return enddate;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setEnddate(final Date timestamp) {
enddate = timestamp;
}
@ApiModelProperty(required = true, value = "tite of the message")
@JsonView({View.Persistence.class, View.Public.class})
public String getTitle() {
return title;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setTitle(final String title) {
this.title = title;
}
@ApiModelProperty(required = true, value = "text of the message")
@JsonView({View.Persistence.class, View.Public.class})
public String getText() {
return text;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setText(final String ttext) {
text = ttext;
}
@ApiModelProperty(required = true, value = "defines the target audience for this motd (one of the following: "
+ "'student', 'tutor', 'loggedIn', 'all')")
@JsonView({View.Persistence.class, View.Public.class})
public String getAudience() {
return audience;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setAudience(final String a) {
audience = a;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getSessionId() {
return sessionId;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setSessionId(final String sessionId) {
this.sessionId = sessionId;
}
@ApiModelProperty(required = true,
value = "when audience equals session, the sessionkey referes to the session the messages belong to")
@JsonView({View.Persistence.class, View.Public.class})
public String getSessionkey() {
return sessionkey;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setSessionkey(final String a) {
sessionkey = a;
}
@ApiModelProperty(required = true, value = "the couchDB ID")
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
@Override
public int hashCode() {
// See http://stackoverflow.com/a/113600
final int prim = 37;
final int result = 42;
return prim * result + this.motdkey.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
final Motd other = (Motd) obj;
return this.getMotdkey().equals(other.getMotdkey());
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import de.thm.arsnova.model.serialization.View;
/**
* Contains a list of MotD IDs a user has acknowledged.
*/
@ApiModel(value = "MotdList", description = "Motd List entity - Contains IDs of MotDs a user has acknowledged")
public class MotdList implements Entity {
private String id;
private String rev;
private String motdkeys;
private String username;
@ApiModelProperty(required = true, value = "the couchDB ID")
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
@ApiModelProperty(required = true, value = "the motdkeylist")
@JsonView({View.Persistence.class, View.Public.class})
public String getMotdkeys() {
return motdkeys;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setMotdkeys(final String motds) {
motdkeys = motds;
}
@ApiModelProperty(required = true, value = "the username")
@JsonView({View.Persistence.class, View.Public.class})
public String getUsername() {
return username;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setUsername(final String u) {
username = u;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,18 +15,24 @@
* 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.entities;
import java.io.Serializable;
import java.util.List;
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
public class Session implements Serializable {
import de.thm.arsnova.model.ScoreOptions;
import de.thm.arsnova.model.serialization.View;
private static final long serialVersionUID = 1L;
private String type;
/**
* Represents a Room (Session).
*/
@ApiModel(value = "Room", description = "Room (Session) entity")
public class Room implements Entity {
private String id;
private String rev;
private String name;
private String shortName;
private String keyword;
......@@ -35,9 +41,9 @@ public class Session implements Serializable {
private long lastOwnerActivity;
private String courseType;
private String courseId;
private List<String> _conflicts;
private long creationTime;
private String learningProgressType = "questions";
private ScoreOptions learningProgressOptions = new ScoreOptions();
private RoomFeature features = new RoomFeature();
private String ppAuthorName;
private String ppAuthorMail;
......@@ -49,141 +55,117 @@ public class Session implements Serializable {
private String ppFaculty;
private String ppLevel;
private String sessionType;
private boolean feedbackLock;
private boolean flipFlashcards;
private String _id;
private String _rev;
/**
* Returns a copy of the given session without any information that identifies a person.
* @param original The session to create a anonymized copy of
* @return
*/
public static Session anonymizedCopy(final Session original) {
final Session copy = new Session();
copy.type = original.type;
copy.name = original.name;
copy.shortName = original.shortName;
copy.keyword = original.keyword;
copy.creator = ""; // anonymous
copy.active = original.active;
copy.lastOwnerActivity = original.lastOwnerActivity;
copy.courseType = original.courseType;
copy.courseId = original.courseId;
copy.creationTime = original.creationTime;
copy.learningProgressType = original.learningProgressType;
// public pool
copy.ppAuthorName = original.ppAuthorName;
copy.ppAuthorMail = original.ppAuthorMail;
copy.ppUniversity = original.ppUniversity;
copy.ppLogo = original.ppLogo;
copy.ppSubject = original.ppSubject;
copy.ppLicense = original.ppLicense;
copy.ppDescription = original.ppDescription;
copy.ppFaculty = original.ppFaculty;
copy.ppLevel = original.ppLevel;
copy.sessionType = original.sessionType;
copy._id = original._id;
copy._rev = original._rev;
return copy;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getRevision() {
return rev;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setRevision(final String rev) {
this.rev = rev;
}
@ApiModelProperty(required = true, value = "the name")
@JsonView({View.Persistence.class, View.Public.class})
public String getName() {
return name;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setName(final String name) {
this.name = name;
}
@ApiModelProperty(required = true, value = "the short name")
@JsonView({View.Persistence.class, View.Public.class})
public String getShortName() {
return shortName;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setShortName(final String shortName) {
this.shortName = shortName;
}
@ApiModelProperty(required = true, value = "the keyword")
@JsonView({View.Persistence.class, View.Public.class})
public String getKeyword() {
return keyword;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setKeyword(final String keyword) {
this.keyword = keyword;
}
@ApiModelProperty(required = true, value = "the session creator")
@JsonView(View.Persistence.class)
public String getCreator() {
return creator;
}
@JsonView(View.Persistence.class)
public void setCreator(final String creator) {
this.creator = creator;
}
@ApiModelProperty(required = true, value = "true for active session")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isActive() {
return active;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setActive(final boolean active) {
this.active = active;
}
@ApiModelProperty(required = true, value = "timestamp from the last activity of the owner")
@JsonView(View.Persistence.class)
public long getLastOwnerActivity() {
return lastOwnerActivity;
}
@JsonView(View.Persistence.class)
public void setLastOwnerActivity(final long lastOwnerActivity) {
this.lastOwnerActivity = lastOwnerActivity;
}
public void set_id(final String id) {
_id = id;
}
public String get_id() {
return _id;
}
public void set_rev(final String rev) {
_rev = rev;
}
public String get_rev() {
return _rev;
}
public void set_conflicts(final List<String> conflicts) {
_conflicts = conflicts;
}
public List<String> get_conflicts() {
return _conflicts;
}
public boolean isCreator(final User user) {
public boolean isCreator(final ClientAuthentication user) {
return user.getUsername().equals(creator);
}
@ApiModelProperty(required = true, value = "the source the course comes from (example: moodle)")
@JsonView({View.Persistence.class, View.Public.class})
public String getCourseType() {
return courseType;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setCourseType(final String courseType) {
this.courseType = courseType;
}
@ApiModelProperty(required = true, value = "the course ID")
@JsonView({View.Persistence.class, View.Public.class})
public String getCourseId() {
return courseId;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setCourseId(final String courseId) {
this.courseId = courseId;
}
......@@ -193,105 +175,183 @@ public class Session implements Serializable {
return getCourseId() != null && !getCourseId().isEmpty();
}
@ApiModelProperty(required = true, value = "creation timestamp")
@JsonView({View.Persistence.class, View.Public.class})
public long getCreationTime() {
return creationTime;
}
public void setCreationTime(long creationTime) {
@JsonView(View.Persistence.class)
public void setCreationTime(final long creationTime) {
this.creationTime = creationTime;
}
public String getLearningProgressType() {
return learningProgressType;
@ApiModelProperty(required = true, value = "the score options")
@JsonView({View.Persistence.class, View.Public.class})
public ScoreOptions getLearningProgressOptions() {
return learningProgressOptions;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setLearningProgressOptions(final ScoreOptions learningProgressOptions) {
this.learningProgressOptions = learningProgressOptions;
}
public void setLearningProgressType(String learningProgressType) {
this.learningProgressType = learningProgressType;
@ApiModelProperty(required = true,
value = "the enabled features (e.g. feedback, interposed, learning Progress, lecture)")
@JsonView({View.Persistence.class, View.Public.class})
public RoomFeature getFeatures() {
return features;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFeatures(final RoomFeature features) {
this.features = features;
}
@ApiModelProperty(required = true, value = "the public pool author name")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpAuthorName() {
return ppAuthorName;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpAuthorName(final String ppAuthorName) {
this.ppAuthorName = ppAuthorName;
}
@ApiModelProperty(required = true, value = "the public pool author email")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpAuthorMail() {
return ppAuthorMail;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpAuthorMail(final String ppAuthorMail) {
this.ppAuthorMail = ppAuthorMail;
}
@ApiModelProperty(required = true, value = "the public pool university")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpUniversity() {
return ppUniversity;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpUniversity(final String ppUniversity) {
this.ppUniversity = ppUniversity;
}
@ApiModelProperty(required = true, value = "the public pool logo")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpLogo() {
return ppLogo;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpLogo(final String ppLogo) {
this.ppLogo = ppLogo;
}
@ApiModelProperty(required = true, value = "used to display subject")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpSubject() {
return ppSubject;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpSubject(final String ppSubject) {
this.ppSubject = ppSubject;
}
@ApiModelProperty(required = true, value = "the public pool license")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpLicense() {
return ppLicense;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpLicense(final String ppLicense) {
this.ppLicense = ppLicense;
}
@ApiModelProperty(required = true, value = "the public pool description")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpDescription() {
return ppDescription;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpDescription(final String ppDescription) {
this.ppDescription = ppDescription;
}
@ApiModelProperty(required = true, value = "the public pool faculty")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpFaculty() {
return ppFaculty;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpFaculty(final String ppFaculty) {
this.ppFaculty = ppFaculty;
}
@ApiModelProperty(required = true, value = "the public pool level")
@JsonView({View.Persistence.class, View.Public.class})
public String getPpLevel() {
return ppLevel;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPpLevel(final String ppLevel) {
this.ppLevel = ppLevel;
}
@ApiModelProperty(required = true, value = "the session type")
@JsonView({View.Persistence.class, View.Public.class})
public String getSessionType() {
return sessionType;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setSessionType(final String sessionType) {
this.sessionType = sessionType;
}
@ApiModelProperty(required = true, value = "the feedback lock status")
@JsonView({View.Persistence.class, View.Public.class})
public boolean getFeedbackLock() {
return feedbackLock;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFeedbackLock(final Boolean lock) {
this.feedbackLock = lock;
}
@ApiModelProperty(required = true, value = "the flashcard flip condition")
@JsonView({View.Persistence.class, View.Public.class})
public boolean getFlipFlashcards() {
return flipFlashcards;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFlipFlashcards(final Boolean flip) {
this.flipFlashcards = flip;
}
public boolean hasAuthorDetails() {
return ppAuthorName != null && !ppAuthorName.isEmpty()
|| ppAuthorMail != null && !ppAuthorMail.isEmpty()
|| ppUniversity != null && !ppUniversity.isEmpty()
|| ppFaculty != null && !ppFaculty.isEmpty()
|| ppLogo != null && !ppLogo.isEmpty();
}
@Override
public String toString() {
return "Session [keyword=" + keyword + ", type=" + type + ", creator=" + creator + "]";
return "Room [keyword=" + keyword + ", type=" + getType() + ", creator=" + creator + "]";
}
@Override
......@@ -304,11 +364,11 @@ public class Session implements Serializable {
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
Session other = (Session) obj;
final Room other = (Room) obj;
return this.keyword.equals(other.keyword);
}
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import de.thm.arsnova.model.serialization.View;
/**
* Contains fields that describe which specific Feature is activated for a Room.
*/
@ApiModel(value = "RoomFeature",
description = "Room (Session) Feature entity - Represents feature/use case settings of a Room")
public class RoomFeature implements Serializable {
private boolean custom = false;
private boolean clicker = false;
private boolean peerGrading = false;
private boolean twitterWall = false;
private boolean liveFeedback = false;
private boolean interposedFeedback = false;
private boolean liveClicker = false;
private boolean flashcard = false;
private boolean total = false;
private boolean jitt = false;
private boolean lecture = false;
private boolean feedback = false;
private boolean interposed = false;
private boolean pi = false;
private boolean learningProgress = false;
private boolean flashcardFeature = false;
private boolean slides = false;
public RoomFeature(final RoomFeature features) {
this();
if (features != null) {
this.custom = features.custom;
this.clicker = features.clicker;
this.peerGrading = features.peerGrading;
this.twitterWall = features.twitterWall;
this.liveFeedback = features.liveFeedback;
this.interposedFeedback = features.interposedFeedback;
this.liveClicker = features.liveClicker;
this.flashcardFeature = features.flashcardFeature;
this.flashcard = features.flashcard;
this.total = features.total;
this.lecture = features.lecture;
this.jitt = features.jitt;
this.feedback = features.feedback;
this.interposed = features.interposed;
this.pi = features.pi;
this.learningProgress = features.learningProgress;
this.slides = features.slides;
}
}
public RoomFeature() {
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isLecture() {
return lecture;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setLecture(final boolean lecture) {
this.lecture = lecture;
}
@ApiModelProperty(required = true, value = "jitt")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isJitt() {
return jitt;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setJitt(final boolean jitt) {
this.jitt = jitt;
}
@ApiModelProperty(required = true, value = "feedback")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isFeedback() {
return feedback;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFeedback(final boolean feedback) {
this.feedback = feedback;
}
@ApiModelProperty(required = true, value = "interposed")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isInterposed() {
return interposed;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setInterposed(final boolean interposed) {
this.interposed = interposed;
}
@ApiModelProperty(required = true, value = "peer instruction")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isPi() {
return pi;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPi(final boolean pi) {
this.pi = pi;
}
@ApiModelProperty(required = true, value = "score")
@JsonView({View.Persistence.class, View.Public.class})
public boolean isLearningProgress() {
return learningProgress;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setLearningProgress(final boolean learningProgress) {
this.learningProgress = learningProgress;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isCustom() {
return custom;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setCustom(final boolean custom) {
this.custom = custom;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isClicker() {
return clicker;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setClicker(final boolean clicker) {
this.clicker = clicker;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isPeerGrading() {
return peerGrading;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setPeerGrading(final boolean peerGrading) {
this.peerGrading = peerGrading;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isFlashcardFeature() {
return flashcardFeature;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFlashcardFeature(final boolean flashcardFeature) {
this.flashcardFeature = flashcardFeature;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isFlashcard() {
return flashcard;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setFlashcard(final boolean flashcard) {
this.flashcard = flashcard;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isTotal() {
return total;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setTotal(final boolean total) {
this.total = total;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isLiveFeedback() {
return liveFeedback;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setLiveFeedback(final boolean liveFeedback) {
this.liveFeedback = liveFeedback;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isInterposedFeedback() {
return interposedFeedback;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setInterposedFeedback(final boolean interposedFeedback) {
this.interposedFeedback = interposedFeedback;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isLiveClicker() {
return liveClicker;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setLiveClicker(final boolean liveClicker) {
this.liveClicker = liveClicker;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isTwitterWall() {
return twitterWall;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setTwitterWall(final boolean twitterWall) {
this.twitterWall = twitterWall;
}
@JsonView({View.Persistence.class, View.Public.class})
public boolean isSlides() {
return slides;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setSlides(final boolean slides) {
this.slides = slides;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 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
......@@ -15,12 +15,23 @@
* 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.entities;
package de.thm.arsnova.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.List;
public class SessionInfo {
import de.thm.arsnova.model.serialization.View;
/**
* Summary information of a specific Room. For example, this is used to display list entries of a user's Rooms as well
* as a user's Room History (Visited Rooms).
*/
@ApiModel(value = "RoomInfo", description = "Room (Session) Info entity")
public class RoomInfo {
private String name;
private String shortName;
......@@ -34,142 +45,176 @@ public class SessionInfo {
private int numQuestions;
private int numAnswers;
private int numInterposed;
private int numUnredInterposed;
private int numComments;
private int numUnreadComments;
private int numUnanswered;
public SessionInfo(Session session) {
this.name = session.getName();
this.shortName = session.getShortName();
this.keyword = session.getKeyword();
this.active = session.isActive();
this.courseType = session.getCourseType();
this.creationTime = session.getCreationTime();
this.sessionType = session.getSessionType();
this.ppLevel = session.getPpLevel();
this.ppSubject = session.getPpSubject();
public RoomInfo(final Room room) {
this.name = room.getName();
this.shortName = room.getShortName();
this.keyword = room.getKeyword();
this.active = room.isActive();
this.courseType = room.getCourseType();
this.creationTime = room.getCreationTime();
this.sessionType = room.getSessionType();
this.ppLevel = room.getPpLevel();
this.ppSubject = room.getPpSubject();
}
public SessionInfo() {}
public RoomInfo() {
}
public static List<SessionInfo> fromSessionList(List<Session> sessions) {
List<SessionInfo> infos = new ArrayList<SessionInfo>();
for (Session s : sessions) {
infos.add(new SessionInfo(s));
public static List<RoomInfo> fromSessionList(final List<Room> sessions) {
final List<RoomInfo> infos = new ArrayList<>();
for (final Room s : sessions) {
infos.add(new RoomInfo(s));
}
return infos;
}
@ApiModelProperty(required = true, value = "the name")
@JsonView(View.Public.class)
public String getName() {
return name;
}
public void setName(String name) {
public void setName(final String name) {
this.name = name;
}
@ApiModelProperty(required = true, value = "the short name")
@JsonView(View.Public.class)
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
public void setShortName(final String shortName) {
this.shortName = shortName;
}
@ApiModelProperty(required = true, value = "the keyword")
@JsonView(View.Public.class)
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
public void setKeyword(final String keyword) {
this.keyword = keyword;
}
@ApiModelProperty(required = true, value = "true for active")
@JsonView(View.Public.class)
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
public void setActive(final boolean active) {
this.active = active;
}
@ApiModelProperty(required = true, value = "the source the course comes from (example: moodle)")
@JsonView(View.Public.class)
public String getCourseType() {
return courseType;
}
public void setCourseType(String courseType) {
public void setCourseType(final String courseType) {
this.courseType = courseType;
}
@ApiModelProperty(required = true, value = "the session type")
@JsonView(View.Public.class)
public String getSessionType() {
return sessionType;
}
public void setSessionType(String sessionType) {
public void setSessionType(final String sessionType) {
this.sessionType = sessionType;
}
@ApiModelProperty(required = true, value = "used to display level")
@JsonView(View.Public.class)
public String getPpLevel() {
return ppLevel;
}
public void setPpLevel(String ppLevel) {
public void setPpLevel(final String ppLevel) {
this.ppLevel = ppLevel;
}
@ApiModelProperty(required = true, value = "the public pool subject")
@JsonView(View.Public.class)
public String getPpSubject() {
return ppSubject;
}
public void setPpSubject(String ppSubject) {
public void setPpSubject(final String ppSubject) {
this.ppSubject = ppSubject;
}
@ApiModelProperty(required = true, value = "the number of questions")
@JsonView(View.Public.class)
public int getNumQuestions() {
return numQuestions;
}
public void setNumQuestions(int numQuestions) {
public void setNumQuestions(final int numQuestions) {
this.numQuestions = numQuestions;
}
@ApiModelProperty(required = true, value = "the number of answers")
@JsonView(View.Public.class)
public int getNumAnswers() {
return numAnswers;
}
public void setNumAnswers(int numAnswers) {
public void setNumAnswers(final int numAnswers) {
this.numAnswers = numAnswers;
}
/* Still named "Interposed" instead of "Comments" here for compatibilty reasons. */
@ApiModelProperty(required = true, value = "used to display comment number")
@JsonView(View.Public.class)
public int getNumInterposed() {
return numInterposed;
return numComments;
}
public void setNumInterposed(int numInterposed) {
this.numInterposed = numInterposed;
/* Still named "Interposed" instead of "Comments" here for compatibilty reasons. */
public void setNumInterposed(final int numComments) {
this.numComments = numComments;
}
@ApiModelProperty(required = true, value = "the number of unanswered questions")
@JsonView(View.Public.class)
public int getNumUnanswered() {
return numUnanswered;
}
public void setNumUnanswered(int numUnanswered) {
public void setNumUnanswered(final int numUnanswered) {
this.numUnanswered = numUnanswered;
}
@ApiModelProperty(required = true, value = "the creation timestamp")
@JsonView(View.Public.class)
public long getCreationTime() {
return creationTime;
}
public void setCreationTime(long creationTime) {
public void setCreationTime(final long creationTime) {
this.creationTime = creationTime;
}
/* Still named "Interposed" instead of "Comments" here for compatibilty reasons. */
@ApiModelProperty(required = true, value = "the number of unread comments")
@JsonView(View.Public.class)
public int getNumUnredInterposed() {
return numUnredInterposed;
return numUnreadComments;
}
public void setNumUnredInterposed(int numUnredInterposed) {
this.numUnredInterposed = numUnredInterposed;
/* Still named "Interposed" instead of "Comments" here for compatibilty reasons. */
public void setNumUnredInterposed(final int numUnreadComments) {
this.numUnreadComments = numUnreadComments;
}
@Override
......@@ -182,14 +227,18 @@ public class SessionInfo {
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
// auto generated!
if (this == obj) return true;
if (obj == null) return false;
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SessionInfo other = (SessionInfo) obj;
final RoomInfo other = (RoomInfo) obj;
if (keyword == null) {
if (other.keyword != null) {
return false;
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.migration.v2;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.annotations.ApiModel;
import de.thm.arsnova.model.serialization.View;
/**
* A Room (Session) a user has visited previously.
*/
@ApiModel(value = "VisitedRoom",
description = "Visited Room (Session) entity - An entry of the Room History for the Logged In entity")
public class VisitedRoom {
@JsonProperty("_id")
private String id;
private String name;
private String keyword;
public VisitedRoom() {
}
public VisitedRoom(final Room s) {
this.id = s.getId();
this.name = s.getName();
this.keyword = s.getKeyword();
}
@JsonView({View.Persistence.class, View.Public.class})
public String getId() {
return id;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setId(final String id) {
this.id = id;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getName() {
return name;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setName(final String name) {
this.name = name;
}
@JsonView({View.Persistence.class, View.Public.class})
public String getKeyword() {
return keyword;
}
@JsonView({View.Persistence.class, View.Public.class})
public void setKeyword(final String keyword) {
this.keyword = keyword;
}
@Override
public String toString() {
return "VisitedRoom [id=" + id + ", name=" + name + ", keyword="
+ keyword + "]";
}
}
/**
* Classes to translate objects to and from JSON.
*/
package de.thm.arsnova.model;
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 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.model.serialization;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.thm.arsnova.model.Entity;
@JsonIgnoreProperties(value = {"type"}, allowGetters = true)
public abstract class CouchDbDocumentMixIn {
@JsonProperty("_id")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
abstract String getId();
@JsonProperty("_id")
abstract void setId(String id);
@JsonProperty("_rev")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
abstract String getRevision();
@JsonProperty("_rev")
abstract String setRevision(String rev);
@JsonSerialize(converter = CouchDbTypeFieldConverter.class)
abstract Class<? extends Entity> getType();
}