Skip to content

Commit

Permalink
Merge pull request #180 from rwth-acis/develop
Browse files Browse the repository at this point in the history
Add Gamification and priority labels
  • Loading branch information
Tobasco99 authored May 10, 2023
2 parents d9f667d + f6901bc commit 93ec0ea
Show file tree
Hide file tree
Showing 28 changed files with 1,318 additions and 2,082 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ the [GitHub Release Page](https://github.com/rwth-acis/RequirementsBazaar/releas

## [Unreleased]

## [0.17.0] - 2023-05-10

### Added

- Added gamification
[d758be2b4a66bd943665c097eee963c65a7dc68e](https://github.com/rwth-acis/RequirementsBazaar/commit/d758be2b4a66bd943665c097eee963c65a7dc68e)
- Added priority labels
[#179](https://github.com/rwth-acis/RequirementsBazaar/pull/179)

## [0.16.0] - 2022-10-05

### Changed

- Upgraded to las2peer 1.2.3 and Java 17
[#175](https://github.com/rwth-acis/RequirementsBazaar/pull/175)
- Fixed bug which caused new users being unable to login
[#173](https://github.com/rwth-acis/RequirementsBazaar/issues/173)


## [0.15.0] - 2022-08-07

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ However you'll have to apply the migrations with liquibase manually to this data

The build and test process is done with gradle. A simple `gradle build` should be sufficient to build the project and run the test cases.

You may have to adjust either your global java environment or the one in your IDE to use Java 14 or the built asset won't start.
You may have to adjust either your global java environment or the one in your IDE to use Java 17 or the built asset won't start.

### Debugging

Expand Down
5 changes: 5 additions & 0 deletions etc/de.rwth.dbis.acis.bazaar.service.BazaarService.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ smtpServer=
emailFromAddress=
emailSummaryTimePeriodInMinutes=
monitor=
gfBaseUrl=
gfUsername=
gfPassword=
gfGameId=
gfNamespace=
4 changes: 2 additions & 2 deletions reqbaz/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ application {
}

repositories {
// Use JCenter for resolving dependencies.
jcenter()
mavenCentral()

// DBIS Archiva
maven {
Expand All @@ -50,6 +49,7 @@ repositories {

dependencies {
implementation 'org.jetbrains:annotations:20.1.0'
implementation 'org.liquibase:liquibase-core:4.20.0'

// Use JUnit test framework.
testImplementation 'junit:junit:4.13'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ monitor=''
twitterApiKey=
twitterApiKeySecret=
twitterClientId=
twitterClientSecret=
twitterClientSecret=
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import de.rwth.dbis.acis.bazaar.service.exception.ErrorCode;
import de.rwth.dbis.acis.bazaar.service.exception.ExceptionHandler;
import de.rwth.dbis.acis.bazaar.service.exception.ExceptionLocation;
import de.rwth.dbis.acis.bazaar.service.gamification.GamificationManager;
import de.rwth.dbis.acis.bazaar.service.internalization.Localization;
import de.rwth.dbis.acis.bazaar.service.notification.ActivityDispatcher;
import de.rwth.dbis.acis.bazaar.service.notification.EmailDispatcher;
Expand All @@ -52,7 +53,6 @@
import i5.las2peer.restMapper.RESTService;
import i5.las2peer.restMapper.annotations.ServicePath;
import io.swagger.annotations.*;
import lombok.Getter;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.http.client.utils.URIBuilder;
import org.jooq.SQLDialect;
Expand Down Expand Up @@ -91,6 +91,7 @@ public class BazaarService extends RESTService {
private final List<BazaarFunctionRegistrar> functionRegistrar;
private final NotificationDispatcher notificationDispatcher;
private final TweetDispatcher tweetDispatcher;
private final GamificationManager gamificationManager;
private final DataSource dataSource;

//CONFIG PROPERTIES
Expand All @@ -111,6 +112,12 @@ public class BazaarService extends RESTService {
protected String twitterClientId;
protected String twitterClientSecret;

protected String gfBaseUrl;
protected String gfUsername;
protected String gfPassword;
protected String gfGameId;
protected String gfNamespace;

public BazaarService() throws Exception {
setFieldValues();
Locale locale = new Locale(lang, country);
Expand Down Expand Up @@ -166,9 +173,10 @@ public BazaarService() throws Exception {
}

tweetDispatcher = new TweetDispatcher(this, twitterApiKey, twitterApiKeySecret, twitterClientId, twitterClientSecret);

new WeeklyNewProjectsTweetTask(this).schedule(timer);

gamificationManager = new GamificationManager(gfBaseUrl, gfUsername, gfPassword, gfGameId, gfNamespace);

notificationDispatcher.setBazaarService(this);
}

Expand Down Expand Up @@ -236,6 +244,10 @@ public TweetDispatcher getTweetDispatcher() {
return tweetDispatcher;
}

public GamificationManager getGamificationManager() {
return gamificationManager;
}

private void registerUserAtFirstLogin() throws Exception {
Agent agent = Context.getCurrent().getMainAgent();

Expand Down Expand Up @@ -274,6 +286,8 @@ private void registerUserAtFirstLogin() throws Exception {
int userId = user.getId();
// this.getNotificationDispatcher().dispatchNotification(user.getCreationDate(), Activity.ActivityAction.CREATE, MonitoringEvent.SERVICE_CUSTOM_MESSAGE_55, userId, Activity.DataType.USER, userId);
dalFacade.addUserToRole(userId, "LoggedInUser", null);
// add new user to gamification and game
gamificationManager.initializeUser(userId);
} else {
// update lastLoginDate
dalFacade.updateLastLoginDate(userIdByLAS2PeerId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public Project createProject(Project project, int userId) throws Exception {
// TODO: concurrency transaction -> https://www.jooq.org/doc/3.9/manual/sql-execution/transaction-management/
addUserToRole(userId, "ProjectAdmin", newProject.getId());

// This is stupid, but the return value of update is inclomplete (dependent objects won't be resolved, since only the top level get by id method is called.
// This is stupid, but the return value of update is incomplete (dependent objects won't be resolved, since only the top level get by id method is called).
// Call repository get separately
projectRepository.update(newProject);
return projectRepository.findById(newProject.getId(), userId);
Expand Down Expand Up @@ -343,92 +343,112 @@ public Requirement modifyRequirement(Requirement modifiedRequirement, int userId

if (modifiedRequirement.getCategories() != null) {
List<Category> oldCategories = listCategoriesByRequirementId(modifiedRequirement.getId(), userId);
handleOldCategory(modifiedRequirement, oldCategories);
handleNewCategory(modifiedRequirement, oldCategories);
}
synchronizeTags(modifiedRequirement, oldRequirement);
synchronizeAttachments(modifiedRequirement, userId, oldRequirement);

return getRequirementById(modifiedRequirement.getId(), userId);
}

private void handleNewCategory(Requirement modifiedRequirement, List<Category> oldCategories) throws BazaarException {
for (Integer newCategory : modifiedRequirement.getCategories()) {
boolean containCategory = false;
for (Category oldCategory : oldCategories) {
boolean containCategory = false;
for (Integer newCategory : modifiedRequirement.getCategories()) {
if (oldCategory.getId() == newCategory) {
containCategory = true;
break;
}
}
if (!containCategory) {
deleteCategoryTag(modifiedRequirement.getId(), oldCategory.getId());
if (oldCategory.getId() == newCategory) {
containCategory = true;
break;
}
}
if (!containCategory) {
addCategoryTag(modifiedRequirement.getId(), newCategory);
}
}
}

private void handleOldCategory(Requirement modifiedRequirement, List<Category> oldCategories) throws BazaarException {
for (Category oldCategory : oldCategories) {
boolean containCategory = false;
for (Integer newCategory : modifiedRequirement.getCategories()) {
boolean containCategory = false;
for (Category oldCategory : oldCategories) {
if (oldCategory.getId() == newCategory) {
containCategory = true;
break;
}
}
if (!containCategory) {
addCategoryTag(modifiedRequirement.getId(), newCategory);
if (oldCategory.getId() == newCategory) {
containCategory = true;
break;
}
}
if (!containCategory) {
deleteCategoryTag(modifiedRequirement.getId(), oldCategory.getId());
}
}
}

// Synchronize tags
if (modifiedRequirement.getTags() != null) {
private void synchronizeAttachments(Requirement modifiedRequirement, int userId, Requirement oldRequirement) {
if (modifiedRequirement.getAttachments() != null) {
// Check if tags have changed
for (Tag tag : modifiedRequirement.getTags()) {
try {
Tag internalTag = getTagById(tag.getId());

// Check if tag exists (in project)
if (internalTag == null || modifiedRequirement.getProjectId() != internalTag.getProjectId()) {
tag.setProjectId(modifiedRequirement.getProjectId());
tag = createTag(tag);
}
tagRequirement(tag.getId(), modifiedRequirement.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
checkTagChangesAttachments(modifiedRequirement, userId);

// Remove tags no longer present
oldRequirement.getTags().stream().filter(tag -> modifiedRequirement.getTags().contains(tag)).forEach(tag -> {
oldRequirement.getAttachments().stream().filter(attachment -> modifiedRequirement.getAttachments().contains(attachment)).forEach(attachment -> {
try {
untagRequirement(tag.getId(), oldRequirement.getId());
deleteAttachmentById(attachment.getId());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

// Synchronize attachments
if (modifiedRequirement.getAttachments() != null) {
// Check if tags have changed
for (Attachment attachment : modifiedRequirement.getAttachments()) {
try {
Attachment internalAttachment = null;
if (attachment.getId() != 0) {
internalAttachment = getAttachmentById(attachment.getId());
}

// Check if attachment exists, otherwise create
if (internalAttachment == null) {
attachment.setRequirementId(modifiedRequirement.getId());
attachment.setCreator(getUserById(userId));
createAttachment(attachment);
}
} catch (Exception e) {
e.printStackTrace();
private void checkTagChangesAttachments(Requirement modifiedRequirement, int userId) {
for (Attachment attachment : modifiedRequirement.getAttachments()) {
try {
Attachment internalAttachment = null;
if (attachment.getId() != 0) {
internalAttachment = getAttachmentById(attachment.getId());
}

// Check if attachment exists, otherwise create
if (internalAttachment == null) {
attachment.setRequirementId(modifiedRequirement.getId());
attachment.setCreator(getUserById(userId));
createAttachment(attachment);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

private void synchronizeTags(Requirement modifiedRequirement, Requirement oldRequirement) {
if (modifiedRequirement.getTags() != null) {
// Check if tags have changed
checkTagChanges(modifiedRequirement);

// Remove tags no longer present
oldRequirement.getAttachments().stream().filter(attachment -> modifiedRequirement.getAttachments().contains(attachment)).forEach(attachment -> {
oldRequirement.getTags().stream().filter(tag -> !modifiedRequirement.getTags().contains(tag)).forEach(tag -> {
try {
deleteAttachmentById(attachment.getId());
untagRequirement(tag.getId(), oldRequirement.getId());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

return getRequirementById(modifiedRequirement.getId(), userId);
private void checkTagChanges(Requirement modifiedRequirement) {
for (Tag tag : modifiedRequirement.getTags()) {
try {
Tag internalTag = getTagById(tag.getId());

// Check if tag exists (in project)
if (internalTag == null || modifiedRequirement.getProjectId() != internalTag.getProjectId()) {
tag.setProjectId(modifiedRequirement.getProjectId());
tag = createTag(tag);
}
tagRequirement(tag.getId(), modifiedRequirement.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package de.rwth.dbis.acis.bazaar.service.dal.entities;

import com.fasterxml.jackson.annotation.JsonIgnore;
import de.rwth.dbis.acis.bazaar.service.dal.helpers.UserVote;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.jackson.Jacksonized;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;

@EqualsAndHashCode(callSuper = true)
@Data
Expand All @@ -26,6 +25,10 @@ public class Dashboard extends EntityBase {
@NotNull
private List<Requirement> requirements;

private List<Map<String, Object>> badges;

private Map<String, Object> status;

@JsonIgnore
@Override
public int getId() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import de.rwth.dbis.acis.bazaar.service.dal.helpers.SerializerViews;
import org.apache.commons.lang3.Validate;

import java.util.List;
import java.util.Map;

/**
* @since 9/16/2014
*/
public abstract class EntityBase implements IdentifiedById {

private List<Map<String, Object>> gamificationNotifications;

public String toJSON() throws JsonProcessingException {
return new ObjectMapper().registerModule(new JavaTimeModule())
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
Expand All @@ -45,4 +51,14 @@ public String toPrivateJSON() throws JsonProcessingException {
.writerWithView(SerializerViews.Private.class)
.writeValueAsString(this);
}

public void setGamificationNotifications(List<Map<String, Object>> gamificationNotifications) {
Validate.notNull(gamificationNotifications);
// prevent field to be sent if its empty
this.gamificationNotifications = gamificationNotifications.size() == 0 ? null : gamificationNotifications;
}

public List<Map<String, Object>> getGamificationNotifications() {
return gamificationNotifications;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.rwth.dbis.acis.bazaar.service.dal.entities;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
Expand All @@ -22,6 +21,5 @@ public class Tag extends EntityBase {
@NotNull
private String colour;

@JsonIgnore
private Integer projectId;
}
Loading

0 comments on commit 93ec0ea

Please sign in to comment.