Compare commits

..

100 Commits

Author SHA1 Message Date
Sheldan
89a3afd10e [maven-release-plugin] prepare release abstracto-application-1.2.15 2021-06-02 00:45:51 +02:00
Sheldan
793a1c3657 [AB-284] resizing warn length and changing default date behaviour for mute 2021-06-02 00:36:36 +02:00
Sheldan
7fdb87ef1f [AB-284] adding warn decay notification
adding default mute reason
fixing incorrect muting user being stored
2021-06-01 23:38:06 +02:00
Sheldan
2f8e7c3947 [AB-282] adding okhttp interceptor to log requests 2021-06-01 21:44:03 +02:00
Sheldan
3bf761a2e5 [AB-281] adding ban and unban command
removing banId command in favor of the normal ban command
removing various feature modes for moderation for clearer configuration
2021-06-01 21:10:17 +02:00
Sheldan
55e0879e06 [AB-277] adding report mechanism via reactions 2021-05-30 21:00:49 +02:00
Sheldan
d69f597663 [AB-279] extending max level for experience gain to 150 2021-05-30 20:00:06 +02:00
Sheldan
148c25da4c [AB-275] fixing channel groups not being able to be found, because of upper/lowercase
adding performance improvements for experience listener
adding logging to when a user gains a level
fixing creating a user experience instance in the join listener, which was not persisted
2021-05-29 01:09:14 +02:00
Sheldan
f3bb9b9a69 [AB-276] enabling to cache more members in JDA to reduce requests 2021-05-29 00:56:02 +02:00
Sheldan
0366d48764 [maven-release-plugin] prepare for next development iteration 2021-05-26 21:51:42 +02:00
Sheldan
118b4c0e5d [maven-release-plugin] prepare release abstracto-application-1.2.14 2021-05-26 21:51:33 +02:00
Sheldan
95a639a733 [AB-272] improving leaderboard performance
fixing leaderboard returning wrong pages
making template cache update duration longer
2021-05-26 21:41:04 +02:00
Sheldan
919b52a607 [maven-release-plugin] prepare for next development iteration 2021-05-26 14:48:13 +02:00
Sheldan
a9229d4b28 [maven-release-plugin] prepare release abstracto-application-1.2.13 2021-05-26 14:48:06 +02:00
Sheldan
47ce03ac25 [AB-xxx] fixing version 2021-05-26 14:37:57 +02:00
Sheldan
cef96515aa Revert "[maven-release-plugin] prepare release abstracto-application-1.3.13"
This reverts commit 072d680e
2021-05-26 14:16:21 +02:00
Sheldan
23ac70bb69 [maven-release-plugin] prepare for next development iteration 2021-05-26 13:52:20 +02:00
Sheldan
072d680e2f [maven-release-plugin] prepare release abstracto-application-1.3.13 2021-05-26 13:52:11 +02:00
Sheldan
04b3e073aa [AB-270] fixing test 2021-05-26 11:51:45 +02:00
Sheldan
08e2a31f15 [AB-270] adding a channel group to define the channels in which experience gain is disabled
adding a service method to enable migration
2021-05-26 11:29:34 +02:00
Sheldan
184271ff7c [AB-247/AB-252] fixing issue with set experience role failing to consider the correct experience roles
adding levelRoles command
ignoring bots from experience gain
adding a bit more logging to user experience handling
2021-05-26 01:22:37 +02:00
Sheldan
c4fe73b3f8 [AB-251] adding optional member parameter to rank command to show the rank of another member 2021-05-25 00:24:07 +02:00
Sheldan
2dc73ef3b9 [AB-267] fixing some combinations of reaction characters being ignored 2021-05-24 19:05:41 +02:00
Sheldan
2dd02cdae8 [AB-266] fixing online status and activity not showing up in userinfo 2021-05-24 18:32:41 +02:00
Sheldan
d39ee4359f [AB-231] fixing parameter letting less than required commands to the commands, in case the parameters were not able to be parsed (expected emote got string), the check for parameter count as only done before actually parsing the parameters 2021-05-24 18:16:39 +02:00
Sheldan
d7cc7f579f [AB-254] fixing exception for unSuggest in case the suggestion message has been deleted 2021-05-24 17:53:58 +02:00
Sheldan
7d30afbd2c [AB-262] adding feature mode to suggestion to be automatically reminded of a suggestion after a configurable amount of time 2021-05-24 17:39:19 +02:00
Sheldan
f4c1dcb27f [maven-release-plugin] prepare for next development iteration 2021-05-23 23:26:29 +02:00
Sheldan
fda5262df0 [maven-release-plugin] prepare release abstracto-application-1.2.12 2021-05-23 23:26:21 +02:00
Sheldan
dc2479889a [AB-xxx] making regex checks ignore case 2021-05-23 23:17:29 +02:00
Sheldan
1fbd494590 [AB-xxx] fixing issues related to emote tracking 2021-05-23 22:27:52 +02:00
Sheldan
9dc1d73507 [AB-264] fixing profanity filter not considering message edits 2021-05-23 17:10:54 +02:00
Sheldan
23af59ab9d [AB-261] fixing invite filter only acting in the message received event 2021-05-23 16:45:36 +02:00
Sheldan
13a6e1fdca [AB-263] adding stricter not null checks to database, disabling updates/inserts for created and updated columns to only rely on triggers 2021-05-23 14:17:03 +02:00
Sheldan
04a7cfafd7 [AB-84] adding profanity filter with different feature modes
react command: adding additional mapping for character r
2021-05-16 23:44:50 +02:00
Sheldan
eca9e6ebf7 [AB-258] improving handling of request failures for urban dictionary 2021-05-12 15:38:57 +02:00
Sheldan
d4edbb0d94 [maven-release-plugin] prepare for next development iteration 2021-05-12 00:51:17 +02:00
Sheldan
aff7fda016 [maven-release-plugin] prepare release abstracto-application-1.2.11 2021-05-12 00:51:09 +02:00
Sheldan
976d4473cb [AB-xxx] adding 400 HTTP status to OkHttp metrics
adding convenience creation method to server user
2021-05-12 00:07:44 +02:00
Sheldan
9ebf0f08dd [AB-257] fixing link embed message being deleted while it still contains an attachment
adding more convenience methods to post target services
2021-05-11 12:58:39 +02:00
Sheldan
e31d257e6f [AB-240] changing invite filter to actively filter the server instead of only being based on the code
moving invite filter to separate module
updating to newer liquibase version
changing concept of immune roles which are directly associated to commands to immune roles which are immune against certain effects. these effects can be configured directly by the command (and a condition checks this effect), but they can be used in services as well, unrelated to commands
adding checks to not execute message received listeners for the wrong message types
adding metric support for 502 status
fixing duplicating help entries when two module definitions with the same key are present
2021-05-10 20:45:34 +02:00
Sheldan
9ae35a7e9d [AB-253] removing help example from reset config command 2021-05-04 13:21:27 +02:00
Sheldan
829c109466 [maven-release-plugin] prepare for next development iteration 2021-05-02 23:18:14 +02:00
Sheldan
bfe9b0d82b [maven-release-plugin] prepare release abstracto-application-1.2.10 2021-05-02 23:18:06 +02:00
Sheldan
3b2216201d [AB-174] fixing being unable to snooze unreminded reminders
changing new line handling for command parameters
2021-05-02 23:01:33 +02:00
Sheldan
a05393eb96 [AB-xxx] updating JDA version 2021-05-02 22:22:40 +02:00
Sheldan
da3ce01fc7 [AB-248] rejecting the everyone role as a valid parameter for a role parameter 2021-05-02 21:54:54 +02:00
dependabot[bot]
0683c92782 Bump commons-io from 2.6 to 2.7 in /abstracto-application
Bumps commons-io from 2.6 to 2.7.

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-02 20:36:46 +02:00
Sheldan
a35cc0ab61 [AB-246] fixing new lines being removed from parameters
creating javadoc profile to only build javadoc on release builds
2021-05-02 20:33:23 +02:00
Sheldan
bbae3575f8 [AB-246] skipping parameters after the mandatory have been parsed 2021-05-02 19:50:00 +02:00
Sheldan
2a5c462c35 [AB-246] changing parameter handling to only actually evaluate the necessary parameter handlers, this helps avoiding providing the wrong parameter to the actual command 2021-05-02 17:40:52 +02:00
Sheldan
23dd02312a [AB-250] showing nicer exception in case there is no tracked experience yet 2021-05-02 01:26:39 +02:00
Sheldan
ad15538b67 [AB-244] fixing experience service related test 2021-05-02 00:22:03 +02:00
Sheldan
4c1470b148 [AB-245] roles are required to be sorted when syncing users, this led to incorrect role assignments 2021-05-01 12:55:47 +02:00
Sheldan
3559a823fc [AB-244] always loading the member for giving experience, members are not in cache just for writing a message 2021-05-01 12:52:45 +02:00
Sheldan
fa864f85dd [AB-243] when loading messages we ignore embed links part of a channel/guild which are not available anymore 2021-05-01 12:31:27 +02:00
Sheldan
5a6fac640e [AB-xxx] increasing caching duration for messages 2021-04-29 01:05:27 +02:00
Sheldan
020cc58c4a [AB-242] refactoring suggestions
adding veto and unsuggest command
adding support for configuration whether or not a reply mentions the message
adding support to reply to a message via template
changed default mention config to exclude role mentions
2021-04-29 01:00:27 +02:00
Sheldan
dec398c3f1 [AB-241] fixing test 2021-04-25 21:32:26 +02:00
Sheldan
f097342fed [AB-241] fixing low cooldowns leading to NPE in command cooldown condition
adding more info to command not found exception
2021-04-25 21:27:29 +02:00
Sheldan
68e2dad2ae [AB-174] adding command to re-schedule reminders 2021-04-25 14:46:59 +02:00
Sheldan
2c2e5c02b1 [maven-release-plugin] prepare for next development iteration 2021-04-24 22:12:43 +02:00
Sheldan
39653574e3 [maven-release-plugin] prepare release abstracto-application-1.2.9 2021-04-24 22:12:35 +02:00
Sheldan
460a4663d7 [AB-xxx] fixing string command parameters in combination with attachments, the attachment was still part of the parameters and used normally, if the parameter type is string, attachments are being skipped 2021-04-24 21:50:41 +02:00
Sheldan
eb79522843 [AB-xxx] minor logging updates 2021-04-24 19:54:30 +02:00
Sheldan
40eb516ddf [AB-237] adding job to clean up the cooldown storage 2021-04-24 19:07:02 +02:00
Sheldan
53bef3fdb3 [AB-233] adding feature to handle removed attachments in message edited events
now cloning the cached message for the listeners, in order to not influence the objects when updating it
2021-04-24 18:03:06 +02:00
Sheldan
27763e985d [AB-232] moving logging to separate module
refactoring leave and join listener
2021-04-24 16:00:58 +02:00
Sheldan
fa4c455ca2 [AB-234] allow templates have individual (additional) allowed mention configurations
adding primary keys to command disabled and command cooldown group
exposing service method to retrieve the channel for a post target
2021-04-24 02:05:15 +02:00
Sheldan
49a9598062 [AB-128] adding command cooldowns on server/channel group and member level
fixing channel group names being made lower case before storing
changing channel group deleted to be sync instead
refactoring exceptions and adding exception message to a few
fixing channel group incorrect type using the wrong template
showing more information in list channel groups command
allowing commands to be in any channel group
adding concept of channel group types not allowing channels/commands to be in multiple of the same type
adding structure to retrieve information about channel groups
adding ability to disable channel groups
changing loading of member parameter handler to not use cache
2021-04-19 00:25:42 +02:00
Sheldan
d540ad80a8 [AB-xxx] fixing loading the incorrect message for cleaning up link embed reactions 2021-04-15 23:57:05 +02:00
Sheldan
537fd85be8 [AB-97] adding react command
we are now actively loading messages in case its a parameter, because the provided message is only partially available
2021-04-13 23:47:22 +02:00
Sheldan
23379e4498 [AB-228] fixing member sometimes unavailable in reaction events 2021-04-11 14:31:11 +02:00
Sheldan
b589e88ad4 [AB-xxx] adding documentation for uptime 2021-04-11 00:34:03 +02:00
Sheldan
f870f64137 [maven-release-plugin] prepare for next development iteration 2021-04-11 00:12:08 +02:00
Sheldan
aea3572fb5 [maven-release-plugin] prepare release abstracto-application-1.2.8 2021-04-11 00:12:01 +02:00
Sheldan
b578b0eb6d [AB-xxx] fixing reminders test 2021-04-10 23:57:12 +02:00
Sheldan
7a9aa32332 [AB-xxx] adding reminder display to reminders command to add a link to the existing reminder 2021-04-10 23:39:36 +02:00
Sheldan
8fea80328d [AB-59] adding command received handler test and fixed some scenarios 2021-04-10 22:29:11 +02:00
Sheldan
446a830514 [AB-xxx] adding alternative interface for creating reminders
fixing reminder IDs not being strings for the quartz job
fixing number handling for very large durations
2021-04-10 00:30:58 +02:00
Sheldan
15d2eb8bd9 [AB-229] exposing gateway ping for metrics 2021-04-08 00:37:49 +02:00
Sheldan
e2c86b98b6 [AB-222] adding uptime command
changed necessary intents
2021-04-08 00:07:31 +02:00
Sheldan
400181a280 [AB-225] adding parameter handler for messages
reworking parameter handling in command received handler
adding string parameter handler to explicitly parse strings
2021-04-07 23:16:25 +02:00
Sheldan
c56a037d28 [AB-226] adding caching of referenced messages (only one element on the chain) 2021-04-06 23:38:45 +02:00
Sheldan
dd97503238 [AB-172] updating to JDA 4.2.1_254 and removing deprecated code from guava 2021-04-06 21:11:36 +02:00
Sheldan
e7b1fbe9d1 [AB-209] adding cleanup job for old embedded messages, this job deletes the entries from the database and removes reactions
reducing thread count for listener executor and scheduling
fixing channel deletion listener not being part of a transaction
2021-04-06 20:23:26 +02:00
Sheldan
61d16d5985 [AB-224] fixing not properly ignoring ignored starboard posts leading to re-creation of them 2021-04-06 03:43:24 +02:00
Sheldan
1d3a85ff01 [AB-221] fixing creation of template for deleted users 2021-04-05 14:24:09 +02:00
Sheldan
09c7daf3e0 [maven-release-plugin] prepare for next development iteration 2021-04-05 01:48:20 +02:00
Sheldan
079436a2b6 [maven-release-plugin] prepare release abstracto-application-1.2.7 2021-04-05 01:48:14 +02:00
Sheldan
df1a0cfc02 [AB-xxx] fixing deployment of zip artifacts named the same name being deployed twice 2021-04-05 01:11:45 +02:00
Sheldan
ecc81884e6 [AB-221] fixing embeds and starboard posts not working correctly for deleted users 2021-04-04 23:51:25 +02:00
Sheldan
ff676b29e6 [AB-219] fixing cached message content not being updated
merging message updated listeners
adding clearing message cache to clear cache listener
2021-04-04 22:28:21 +02:00
Sheldan
d088a161ef [AB-xx] adding licenses for google api and youtube services 2021-04-04 18:38:23 +02:00
Sheldan
8258197bfc [AB-xx] replacing trace log with debug 2021-04-04 18:23:18 +02:00
Sheldan
19baf981f1 [AB-217] adding documentation for profanity regex and renaming command for deleting profanity regex from a group 2021-04-04 18:04:23 +02:00
Sheldan
602f0d5bf4 [AB-217] adding profanity service
using profanity service to filter profanities in urban define
adding cache clearing listeners
fixing using 0 as default for maxMessages if not defined
2021-04-04 16:23:13 +02:00
Sheldan
d6bb269ffc [AB-218] fixing templating test 2021-03-30 22:25:46 +02:00
Sheldan
6375dbf463 [AB-218] adding ability to split the normal message as well according to custom configuration
adding ability to define the max amount of messages resulting from a template on a server and template base
fixing not always considering the server when rendering templates in various places
2021-03-30 20:29:13 +02:00
Sheldan
33959d696a [maven-release-plugin] prepare for next development iteration 2021-03-29 03:17:40 +02:00
1093 changed files with 36884 additions and 19276 deletions

View File

@@ -17,7 +17,7 @@ jobs:
id: version
run: echo "version=$(mvn --file abstracto-application/pom.xml -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive exec:exec)" >> $GITHUB_ENV
- name: Publish to GitHub Packages
run: mvn --file abstracto-application/pom.xml -B deploy -P documentation,deployment-docker -Dmaven.wagon.http.pool=false -DskipTests=true
run: mvn --file abstracto-application/pom.xml -B deploy -P documentation,javadoc -Dmaven.wagon.http.pool=false -DskipTests=true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy documentation to GitHub pages

View File

@@ -14,7 +14,7 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
## Technologies
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.1.1_167
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.2.1_262
* [Spring boot](https://github.com/spring-projects/spring-boot) is used as a framework to create standalone application in Java with Java EE methods. (including Dependency injection and more)
* [Hibernate](https://github.com/hibernate/hibernate-orm) is used as a reference implementation of JPA.
* [Freemarker](https://github.com/apache/freemarker) is used as a templating engine. This is used to provide internationalization for user facing text and enable dynamic embed configuration.
@@ -25,7 +25,7 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
* [Liquibase](https://github.com/liquibase/liquibase) is used to manage changes to the database
## Documentation
A detailed documentation of the pure form of Abstracto including the terminology and commands in HTML form is available [here](https://sheldan.github.io/abstracto-docs/). The PDF is available [here](https://sheldan.github.io/abstracto-docs/documentation.pdf)
A detailed documentation of the pure form of Abstracto including the terminology and commands in HTML form is available [here](https://sheldan.github.io/abstracto-docs/current). The PDF is available [here](https://sheldan.github.io/abstracto-docs/current/documentation.pdf)
If you want to view the documentation to an earlier released version you need to append the desired version to the URL. The current version will be available aforementioned URL, but it is not right now, because Abstracto has not been released yet.
## Customization documentation

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -85,10 +85,10 @@ public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) {
log.trace("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
log.debug("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
if (emoteService.isReactionEmoteAEmote(model.getReaction().getReactionEmote(), assignableRole.getEmote())) {
if(assignableRolePlace.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
log.debug("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(model.getUserReacting());
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
}
@@ -103,7 +103,7 @@ public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
}
}
if(!validReaction) {
log.trace("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
log.debug("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
futures.add(reactionService.removeReactionFromMessage(model.getReaction(), model.getMessage(), model.getMemberReacting().getUser()));
}
Long assignableRolePlaceId = assignableRolePlace.getId();
@@ -126,7 +126,7 @@ public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId);
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(serverUser);
if(place.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
log.debug("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
}
AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reaction.getReactionEmote(), place);
@@ -167,7 +167,7 @@ public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
log.error("Failed to remove reaction on place post {} because place is inactive.", assignableRolePlacePostId, throwable);
return null;
});
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
log.debug("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
}
}
return DefaultListenerResult.PROCESSED;

View File

@@ -68,7 +68,7 @@ public class AssignablePostReactionRemoved implements AsyncReactionRemovedListen
});
return DefaultListenerResult.PROCESSED;
} else {
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
log.debug("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
return DefaultListenerResult.PROCESSED;
}
} else {

View File

@@ -152,7 +152,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
boolean emoteUsable = true;
if(fakeEmote.getEmote() != null) {
// it only may be unusable if its a custom emote
log.trace("Using custom emote {} to create assignable role {} for assignable role place {} in server {}.",
log.debug("Using custom emote {} to create assignable role {} for assignable role place {} in server {}.",
fakeEmote.getEmote().getId(), roleId, placeId, serverId);
emoteUsable = emoteService.isEmoteUsableByBot(fakeEmote.getEmote()) && fakeEmote.getEmote().isAvailable();
}
@@ -161,7 +161,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
if(!assignableRolePlace.getMessagePosts().isEmpty()){
log.trace("There are already message posts on for the assignable role place {}.", assignableRolePlace.getId());
log.debug("There are already message posts on for the assignable role place {}.", assignableRolePlace.getId());
AssignableRolePlacePost latestPost = existingMessagePosts.get(assignableRolePlace.getMessagePosts().size() - 1);
AssignablePostMessage model = prepareAssignablePostMessageModel(assignableRolePlace);
boolean forceNewMessage = latestPost.getAssignableRoles().size() >= 20;
@@ -180,11 +180,11 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
if(channelOptional.isPresent()) {
TextChannel textChannel = channelOptional.get();
if(latestPost.getAssignableRoles().size() < 20) {
log.trace("Adding reaction to existing post {} in channel {} in server {} for assignable role place {}.",
log.debug("Adding reaction to existing post {} in channel {} in server {} for assignable role place {}.",
latestPost.getId(), assignableRolePlace.getChannel().getId(), serverId, placeId);
return addReactionToExistingAssignableRolePlacePost(fakeEmote, description, roleId, latestPost, messageToSend, textChannel);
} else {
log.trace("Adding new post to assignable role place {} in channel {} in server {}.",
log.debug("Adding new post to assignable role place {} in channel {} in server {}.",
placeId, assignableRolePlace.getChannel().getId(), server.getId());
return addNewMessageToAssignableRolePlace(placeId, fakeEmote, description, roleId, messageToSend, textChannel);
}
@@ -192,7 +192,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
throw new ChannelNotInGuildException(latestPost.getUsedChannel().getId());
}
} else {
log.trace("Added emote to assignable place {} in server {}, but no message post yet.", placeId, serverId);
log.debug("Added emote to assignable place {} in server {}, but no message post yet.", placeId, serverId);
self.addAssignableRoleInstanceWithoutPost(placeId, roleId, fakeEmote, description, serverId);
}
} else {
@@ -222,10 +222,10 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
int messagePostSize = latestPost.getAssignablePlace().getMessagePosts().size();
return channelService.retrieveMessageInChannel(textChannel, latestPostId)
.thenCompose(message -> {
log.trace("Adding reaction to message {} in server {} for assignable role place {}.", message.getId(), serverId, placeId);
log.debug("Adding reaction to message {} in server {} for assignable role place {}.", message.getId(), serverId, placeId);
return reactionService.addReactionToMessageAsync(fakeEmote.getFakeEmote(), serverId, message);
}).thenCompose(aVoid -> {
log.trace("Editing embed for assignable role place post {} in assignable role place {} in server {}.", latestPostId, placeId, serverId);
log.debug("Editing embed for assignable role place post {} in assignable role place {} in server {}.", latestPostId, placeId, serverId);
MessageEmbed embedToUse = messageToSend.getEmbeds().get(messagePostSize - 1);
return channelService.editEmbedMessageInAChannel(embedToUse, textChannel, latestPostId);
}).thenAccept(message ->
@@ -250,7 +250,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
Long serverId = textChannel.getGuild().getIdLong();
return channelService.sendEmbedToChannel(embedToUse, textChannel)
.thenCompose(message -> {
log.trace("Adding reaction for role {} to newly created message {} for assignable role place {} in server {}.", roleId, message.getId(), placeId, serverId);
log.debug("Adding reaction for role {} to newly created message {} for assignable role place {} in server {}.", roleId, message.getId(), placeId, serverId);
return reactionService.addReactionToMessageAsync(fakeEmote.getFakeEmote(), serverId, message)
.thenAccept(aVoid ->
self.addNewlyCreatedAssignablePlacePost(placeId, description, roleId, message, fakeEmote)
@@ -275,7 +275,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
AssignableRolePlace loadedPlace = rolePlaceManagementService.findByPlaceId(placeId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
log.debug("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
AssignableRolePlacePost newPost = assignableRolePlacePostManagementServiceBean.createAssignableRolePlacePost(loadedPlace, message.getIdLong());
assignableRoleManagementServiceBean.addRoleToPlace(loadedPlace, emote, role, description, newPost);
@@ -298,7 +298,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
log.info("Storing newly created assignable role {} to post {} to assignable role place {} in server {}.", roleId, messageId, placeId, serverId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
log.debug("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description, messageId);
}
@@ -317,7 +317,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
log.info("Storing newly created assignable role {} without post to assignable role place {} in server {}.", roleId, placeId, serverId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
log.debug("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description);
}
@@ -373,9 +373,9 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRole> assignableRoles = assignableRolePlace.getAssignableRoles();
assignableRoles.sort(Comparator.comparing(AssignableRole::getPosition));
Long messageId = post.getId();
log.trace("Removing field describing assignable role {} in assignable role place {} from post {}.", assignableRole.getId(), assignableRolePlace.getId(), messageId);
log.debug("Removing field describing assignable role {} in assignable role place {} from post {}.", assignableRole.getId(), assignableRolePlace.getId(), messageId);
CompletableFuture<Message> fieldEditing = channelService.removeFieldFromMessage(textChannel, messageId, assignableRoles.indexOf(assignableRole));
log.trace("Clearing reaction for emote {} on assignable role post {} in assignable role place {}.", assignableRole.getEmote().getId(), messageId, assignableRolePlace.getId());
log.debug("Clearing reaction for emote {} on assignable role post {} in assignable role place {}.", assignableRole.getEmote().getId(), messageId, assignableRolePlace.getId());
CompletableFuture<Void> reactionRemoval = reactionService.clearReactionFromMessageWithFuture(assignableRole.getEmote(), assignableRolePlace.getServer().getId(), assignableRole.getAssignableRolePlacePost().getUsedChannel().getId(), assignableRole.getAssignableRolePlacePost().getId());
return CompletableFuture.allOf(fieldEditing, reactionRemoval);
} else {
@@ -429,7 +429,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
TextChannel textChannel = channelOptional.get();
Iterator<MessageEmbed> iterator = messageToSend.getEmbeds().iterator();
place.getMessagePosts().forEach(post -> {
log.trace("Refreshing the posts for message post {} in channel {} in assignable role place {} in server {}.", post.getId(), textChannel.getId(), place.getId(), place.getServer().getId());
log.debug("Refreshing the posts for message post {} in channel {} in assignable role place {} in server {}.", post.getId(), textChannel.getId(), place.getId(), place.getServer().getId());
CompletableFuture<Message> messageCompletableFuture = channelService.editEmbedMessageInAChannel(iterator.next(), textChannel, post.getId());
futures.add(messageCompletableFuture);
});
@@ -444,7 +444,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts();
if(!existingMessagePosts.isEmpty()) {
MessageToSend renderedMessage = renderAssignablePlacePosts(place);
log.trace("There are {} current posts known for the assignable role place {}.", existingMessagePosts.size(), place.getId());
log.debug("There are {} current posts known for the assignable role place {}.", existingMessagePosts.size(), place.getId());
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
AssignableRolePlacePost firstPost = existingMessagePosts.get(0);
Long channelId = firstPost.getUsedChannel().getId();
@@ -654,7 +654,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
.position(role.getPosition())
.awardedRole(jdaRole)
.build();
log.trace("Displaying config for role {} with emote {} in position {}.", role.getId(), emoteForRole.getId(), role.getPosition());
log.debug("Displaying config for role {} with emote {} in position {}.", role.getId(), emoteForRole.getId(), role.getPosition());
roles.add(postRole);
}
AssignableRolePlaceConfig configModel = AssignableRolePlaceConfig
@@ -712,10 +712,10 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
log.info("Removing all existing reactions and roles by user {} on assignable role place {} in server {}.", user.getId(), place.getId(), user.getUser().getServerReference().getId());
user.getRoles().forEach(assignableRole -> {
futures.add(roleService.removeAssignableRoleFromUser(assignableRole, user.getUser()));
log.trace("Removing role {} from user {} in server {} because of assignable role clearing.", assignableRole.getRole().getId(), user.getUser().getUserReference().getId(), place.getServer().getId());
log.debug("Removing role {} from user {} in server {} because of assignable role clearing.", assignableRole.getRole().getId(), user.getUser().getUserReference().getId(), place.getServer().getId());
AEmote emoteToUseObject = emoteManagementService.loadEmote(assignableRole.getEmote().getId());
AssignableRolePlacePost assignablePlacePost = assignableRole.getAssignableRolePlacePost();
log.trace("Removing reaction with emote {} from user {} in server {} because of assignable role clearing.", emoteToUseObject.getId(), user.getUser().getUserReference().getId(), place.getServer().getId());
log.debug("Removing reaction with emote {} from user {} in server {} because of assignable role clearing.", emoteToUseObject.getId(), user.getUser().getUserReference().getId(), place.getServer().getId());
futures.add(reactionService.removeReactionOfUserFromMessageWithFuture(emoteToUseObject, place.getServer().getId(),
assignablePlacePost.getUsedChannel().getId(), assignablePlacePost.getId(), user.getUser().getUserReference().getId()));
});
@@ -784,7 +784,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
*/
private MessageToSend renderAssignablePlacePosts(AssignableRolePlace place) {
AssignablePostMessage model = prepareAssignablePostMessageModel(place);
return templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model);
return templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model, place.getServer().getId());
}
/**
@@ -824,7 +824,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
current = rolesToAddIterator.next();
}
} else if(startOfNewMessage && lastAddedRole != null) {
log.trace("Forcing new message for post of assignable role place {}.", place.getId());
log.debug("Forcing new message for post of assignable role place {}.", place.getId());
lastAddedRole.setForceNewMessage(true);
}
}
@@ -879,7 +879,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> addEmotes(List<CompletableFuture<Message>> assignablePlacePostsMessageFutures, Long assignablePlaceId) {
AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
log.info("Adding emotes to assignable role place {}.", innerRolePlace);
log.trace("We have {} posts and {} roles.", assignablePlacePostsMessageFutures.size(), innerRolePlace.getAssignableRoles().size());
log.debug("We have {} posts and {} roles.", assignablePlacePostsMessageFutures.size(), innerRolePlace.getAssignableRoles().size());
List<AssignableRole> roleStream = innerRolePlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList());
List<CompletableFuture<Void>> reactionFutures = new ArrayList<>();
@@ -890,7 +890,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
MessageEmbed embed = sentMessage.getEmbeds().get(0);
List<AssignableRole> firstRoles = roleStream.subList(usedEmotes, usedEmotes + embed.getFields().size());
usedEmotes += embed.getFields().size();
log.trace("Adding {} emotes to message {} for place {}. In total {} were added.", embed.getFields().size(), sentMessage.getId(), innerRolePlace.getId(), usedEmotes);
log.debug("Adding {} emotes to message {} for place {}. In total {} were added.", embed.getFields().size(), sentMessage.getId(), innerRolePlace.getId(), usedEmotes);
List<Integer> usedEmoteIds = firstRoles.stream().map(assignableRole -> assignableRole.getEmote().getId()).collect(Collectors.toList());
CompletableFuture<Void> firstMessageFuture = addingReactionsToAssignableRolePlacePost(sentMessage, usedEmoteIds);
reactionFutures.add(firstMessageFuture);
@@ -925,7 +925,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
Message message = messageCompletableFuture.join();
// this uses the actual embed count as a limit, so this relies on fields to be used for description, if this changes, this needs to be changed
MessageEmbed embed = message.getEmbeds().get(0);
log.trace("Storing post {} with {} fields.", message.getId(), embed.getFields().size());
log.debug("Storing post {} with {} fields.", message.getId(), embed.getFields().size());
List<AssignableRole> firstRoles = rolesToAdd.subList(usedEmotes, usedEmotes + embed.getFields().size());
usedEmotes += embed.getFields().size();
AssignableRolePlacePost post = assignableRolePlacePostManagementServiceBean.createAssignableRolePlacePost(updatedPlace, message.getIdLong());

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="experienceModule" value="(SELECT id FROM module WHERE name = 'assignableRoles')"/>
<property name="experienceFeature" value="(SELECT id FROM feature WHERE key = 'assignableRole')"/>
<changeSet author="Sheldan" id="assignable_roles-commands">

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="module.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role-feature-insertion">
<insert tableName="feature">
<column name="key" value="assignableRole"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role-module-insertion">
<insert tableName="module">
<column name="name" value="assignableRoles"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role-table">
<createTable tableName="assignable_role">
<column autoIncrement="true" name="id" type="BIGINT">
@@ -24,15 +24,17 @@
<constraints nullable="false"/>
</column>
<column name="place_post_id" type="BIGINT">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="description" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="description" type="VARCHAR(255)"/>
<column name="required_level" type="INTEGER"/>
<column name="position" type="INTEGER">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role_place-table">
<createTable tableName="assignable_role_place">
<column autoIncrement="true" name="id" type="BIGINT">
@@ -18,23 +18,25 @@
<constraints nullable="false"/>
</column>
<column name="key" type="VARCHAR(255)">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="text" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="text" type="VARCHAR(255)"/>
<column name="active" type="BOOLEAN">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="inline" type="BOOLEAN">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="unique_roles" type="BOOLEAN">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="auto_remove" type="BOOLEAN">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role_place_post-table">
<createTable tableName="assignable_role_place_post">
<column autoIncrement="true" name="id" type="BIGINT">
@@ -21,7 +21,7 @@
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>

View File

@@ -3,16 +3,16 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assigned_role_user-table">
<createTable tableName="assigned_role_user">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="assigned_role_user_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="assignable_role_place.xml" relativeToChangelogFile="true"/>
<include file="assignable_role_place_post.xml" relativeToChangelogFile="true"/>
<include file="assignable_role.xml" relativeToChangelogFile="true"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="assignableRoles-tables/tables.xml" relativeToChangelogFile="true"/>
<include file="assignableRoles-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,8 +3,8 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.0-assignableRoles/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -257,6 +257,7 @@
<xsd:attributeGroup name="changeLogAttributes">
<xsd:attribute name="logicalFilePath" type="xsd:string"/>
<xsd:attribute name="context" type="xsd:string"/>
<xsd:attribute name="changeLogId" type="xsd:string"/>
<xsd:attribute name="objectQuotingStrategy" type="objectQuotingStrategy" default="LEGACY"/>
</xsd:attributeGroup>
@@ -277,11 +278,12 @@
<xsd:attribute name="created" type="xsd:string"/>
<xsd:attribute name="runOrder" type="xsd:string"/>
<xsd:attribute name="ignore" type="booleanExp"/>
<xsd:attribute name="runWith" type="xsd:string" />
</xsd:attributeGroup>
<!-- Attributes for changes -->
<xsd:attributeGroup name="changeAttributes">
<xsd:anyAttribute namespace="##any" processContents="lax"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:attributeGroup>
<!-- Attributes for constraints -->
@@ -306,7 +308,7 @@
<xsd:attribute name="validateNullable" type="booleanExp"/>
<xsd:attribute name="validateUnique" type="booleanExp"/>
<xsd:attribute name="validatePrimaryKey" type="booleanExp"/>
<xsd:attribute name="validateForeignKey " type="booleanExp"/>
<xsd:attribute name="validateForeignKey" type="booleanExp"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="column">
@@ -420,9 +422,10 @@
<xsd:attribute name="incrementBy" type="xsd:string"/>
<xsd:attribute name="maxValue" type="xsd:string"/>
<xsd:attribute name="minValue" type="xsd:string"/>
<xsd:attribute name="ordered" type="booleanExp"/>
<xsd:attribute name="ordered" type="xsd:string"/>
<xsd:attribute name="cacheSize" type="xsd:string"/>
<xsd:attribute name="cycle" type="booleanExp">
<xsd:attribute name="dataType" type="xsd:string" />
<xsd:attribute name="cycle" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
true for a cycling sequence, false for a non-cycling sequence.
@@ -481,11 +484,15 @@
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="constraintName" type="xsd:string"/>
<xsd:attribute name="dropIndex" type="booleanExp"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="addUniqueConstraint">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="columnNames" type="xsd:string"
@@ -616,6 +623,7 @@
<xsd:attribute name="header" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="allowUpdate" type="booleanExp"/>
<xsd:attribute name="defaultValue" type="xsd:string"/>
<xsd:attribute name="defaultValueNumeric" type="xsd:string"/>
<xsd:attribute name="defaultValueDate" type="xsd:string"/>
@@ -919,6 +927,7 @@
<xsd:attribute name="schemaName" type="xsd:string"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="columnName" type="xsd:string" use="required"/>
<xsd:attribute name="columnDataType" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -957,6 +966,7 @@
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="tablespace" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1124,7 +1134,7 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="tag" type="xsd:string" use="required"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1226,7 +1236,6 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="sequenceAttributes"/>
<xsd:attribute name="dataType" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -1283,7 +1292,7 @@
</xsd:sequence>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="class" type="xsd:string" use="required"/>
<xsd:anyAttribute processContents="lax" />
</xsd:complexType>
</xsd:element>
@@ -1374,4 +1383,4 @@
</xsd:sequence>
</xsd:group>
</xsd:schema>
</xsd:schema>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assignable-roles-int</artifactId>

View File

@@ -29,6 +29,7 @@ public class AssignableRole implements Serializable {
* The unique ID of this {@link AssignableRole assignableRole}
*/
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@@ -36,7 +37,7 @@ public class AssignableRole implements Serializable {
* The {@link AEmote emote} this role is associated with
*/
@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "emote_id")
@JoinColumn(name = "emote_id", nullable = false)
private AEmote emote;
/**
@@ -80,7 +81,7 @@ public class AssignableRole implements Serializable {
/**
* The description which is shown in the embeds of the posts of the {@link AssignableRolePlace}
*/
@Column(name = "description")
@Column(name = "description", nullable = false)
private String description;
/**
@@ -93,18 +94,18 @@ public class AssignableRole implements Serializable {
* The position of this assignable role within the {@link AssignableRole}. This is required in order to show them
* the same order as the descriptions in the fields and also to move them around and switch positions
*/
@Column(name = "position")
@Column(name = "position", nullable = false)
private Integer position;
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created")
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated")
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -33,14 +33,14 @@ public class AssignableRolePlace implements Serializable {
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
@Column(name = "id", nullable = false)
private Long id;
/**
* The channel in which the {@link AssignableRolePlacePost posts} for this place should be created
*/
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="channel_id")
@JoinColumn(name="channel_id", nullable = false)
private AChannel channel;
/**
@@ -53,7 +53,7 @@ public class AssignableRolePlace implements Serializable {
/**
* The key this place is associated with via commands. Unique per server.
*/
@Column(name = "key")
@Column(name = "key", nullable = false)
private String key;
/**
@@ -84,47 +84,47 @@ public class AssignableRolePlace implements Serializable {
/**
* The text which is displayed in the first description area of the created {@link AssignableRolePlacePost}
*/
@Column(name = "text")
@Column(name = "text", nullable = false)
private String text;
/**
* Whether or not the reactions placed onto the posts should be acted upon
*/
@Builder.Default
@Column(name = "active")
@Column(name = "active", nullable = false)
private Boolean active = true;
/**
* Whether or not the fields containing the descriptions should be inline
*/
@Builder.Default
@Column(name = "inline")
@Column(name = "inline", nullable = false)
private Boolean inline = false;
/**
* Whether or not it should be restricted, that a {@link AssignedRoleUser} should only have one role of this place
*/
@Builder.Default
@Column(name = "unique_roles")
@Column(name = "unique_roles", nullable = false)
private Boolean uniqueRoles = false;
/**
* Whether or not the added reactions should be removed automatically
*/
@Builder.Default
@Column(name = "auto_remove")
@Column(name = "auto_remove", nullable = false)
private Boolean autoRemove = false;
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created")
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated")
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -28,14 +28,14 @@ public class AssignableRolePlacePost implements Serializable {
* The ID of the {@link net.dv8tion.jda.api.entities.Message message} which represents this post with the reactions.
*/
@Id
@Column(name = "id")
@Column(name = "id", nullable = false)
private Long id;
/**
* The actual {@link AChannel channel} in which the post ended up in
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "channel_id")
@JoinColumn(name = "channel_id", nullable = false)
private AChannel usedChannel;
/**
@@ -66,13 +66,13 @@ public class AssignableRolePlacePost implements Serializable {
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created")
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated")
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -27,7 +27,7 @@ public class AssignedRoleUser implements Serializable {
* The ID of the associated {@link AUserInAServer userInAServer}
*/
@Id
@Column(name = "id")
@Column(name = "id", nullable = false)
private Long id;
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@@ -48,13 +48,13 @@ public class AssignedRoleUser implements Serializable {
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created")
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated")
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -57,6 +57,10 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>

View File

@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@@ -13,7 +13,7 @@ import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -43,7 +43,7 @@ public class LoveCalc extends AbstractConditionableCommand {
model.setFirstPart(firstPart);
model.setSecondPart(secondPart);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(LOVE_CALC_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored());
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
@@ -58,7 +58,6 @@ public class LoveCalc extends AbstractConditionableCommand {
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -0,0 +1,81 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.command.MockResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.core.command.config.Parameter.ADDITIONAL_TYPES_KEY;
@Component
public class Mock extends AbstractConditionableCommand {
public static final String MOCK_RESPONSE_TEMPLATE_KEY = "mock_response";
@Autowired
private EntertainmentService entertainmentService;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Object givenParameter = commandContext.getParameters().getParameters().get(0);
String messageText;
Member mockedMember = null;
if(givenParameter instanceof Message) {
Message originalMessage = (Message) givenParameter;
messageText = originalMessage.getContentRaw();
mockedMember = originalMessage.getMember();
} else {
messageText = givenParameter.toString();
}
String mockingText = entertainmentService.createMockText(messageText, commandContext.getAuthor(), mockedMember);
MockResponseModel model = (MockResponseModel) ContextConverter.slimFromCommandContext(commandContext, MockResponseModel.class);
model.setOriginalText(messageText);
model.setMockingText(mockingText);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(MOCK_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Map<String, Object> parameterAlternatives = new HashMap<>();
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(Message.class, String.class));
parameters.add(Parameter.builder().name("message").type(CombinedParameter.class).remainder(true)
.additionalInfo(parameterAlternatives).templated(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("mock")
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return EntertainmentFeatureDefinition.ENTERTAINMENT;
}
}

View File

@@ -0,0 +1,74 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ReactionService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.exception.ReactTooManyReactionsException;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class React extends AbstractConditionableCommand {
@Autowired
private EntertainmentService entertainmentService;
@Autowired
private ReactionService reactionService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
Message message = (Message) parameters.get(0);
String text = (String) parameters.get(1);
List<String> reactionChars = entertainmentService.convertTextToEmojis(text);
int existingReactions = message.getReactions().size();
if(reactionChars.size() + existingReactions > Message.MAX_REACTIONS) {
log.error("Message has already {} reactions, {} would be added.", existingReactions, reactionChars.size());
throw new ReactTooManyReactionsException();
}
List<CompletableFuture<Void>> futures = new ArrayList<>();
reactionChars.forEach(s -> futures.add(reactionService.addDefaultReactionToMessageAsync(s, message)));
return FutureUtils.toSingleFutureGeneric(futures)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("message").type(Message.class).templated(true).build());
parameters.add(Parameter.builder().name("text").type(String.class).remainder(true).templated(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("react")
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true)
.causesReaction(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return EntertainmentFeatureDefinition.ENTERTAINMENT;
}
}

View File

@@ -15,7 +15,7 @@ import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.RollResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@@ -12,7 +12,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.model.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@@ -1,16 +1,26 @@
package dev.sheldan.abstracto.entertainment.service;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
import dev.sheldan.abstracto.entertainment.model.ReactMapping;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.*;
@Component
@Slf4j
public class EntertainmentServiceBean implements EntertainmentService {
public static final List<String> EIGHT_BALL_ANSWER_KEYS = Arrays.asList(
@@ -20,12 +30,20 @@ public class EntertainmentServiceBean implements EntertainmentService {
"DONT_COUNT", "REPLY_NO", "SOURCES_NO", "OUTLOOK_NOT_GOOD", "DOUBTFUL" // negative
);
private ReactMapping reactMapping;
@Autowired
private SecureRandom secureRandom;
@Autowired
private ConfigService configService;
@Value("classpath:react_mappings.json")
private Resource reactMappingSource;
@Autowired
private Gson gson;
@Override
public String getEightBallValue(String text) {
return EIGHT_BALL_ANSWER_KEYS.get(secureRandom.nextInt(EIGHT_BALL_ANSWER_KEYS.size()));
@@ -54,4 +72,129 @@ public class EntertainmentServiceBean implements EntertainmentService {
public String takeChoice(List<String> choices, Member memberExecuting) {
return choices.get(secureRandom.nextInt(choices.size()));
}
@Override
public String createMockText(String text, Member memberExecuting, Member mockedUser) {
if(text == null) {
return "";
}
char[] textChars = text.toLowerCase().toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0, textCharsLength = textChars.length; i < textCharsLength; i++) {
char character = textChars[i];
if(i % 2 == 0) {
sb.append(Character.toUpperCase(character));
} else {
sb.append(character);
}
}
return sb.toString();
}
@Override
public List<String> convertTextToEmojis(String text) {
return convertTextToEmojis(text, false);
}
@Override
public String convertTextToEmojisAString(String text) {
return String.join("", convertTextToEmojis(text));
}
@Override
public List<String> convertTextToEmojis(String text, boolean allowDuplicates) {
if(text == null) {
return new ArrayList<>();
}
text = text.toLowerCase();
// we have to have a separate set to check for combo duplicates, because the checks are different:
// first check is if we already used it as an replacement
// the second check below is whether or not we used it as a replacement, that way we allow
// unicode cars from users as well, this leads to things like sos[sos] not being allowed, because the
// unicode chars get removed, and the first sos gets replaced with the unicode
Set<String> replacedCombos = new HashSet<>();
List<String> result = new ArrayList<>();
// this is used to replace the replacements for more than one character
for (String s : this.reactMapping.getCombinationKeys()) {
if (text.contains(s)) {
String replacement = this.reactMapping.getCombination().get(s);
if(!replacedCombos.contains(replacement) || allowDuplicates) {
if(allowDuplicates) {
text = text.replaceAll(s, replacement);
} else {
text = text.replaceFirst(s, replacement);
}
replacedCombos.add(replacement);
}
}
}
log.debug("Replaced {} combos.", replacedCombos.size());
Set<String> usedReplacements = new HashSet<>();
char[] split = text.toCharArray();
for (int i = 0, splitLength = split.length; i < splitLength; i++) {
char normalCharacter = split[i];
String charAsString = Character.toString(normalCharacter);
// the split, also splits surrogate chars (naturally), therefore we need this additional checks
// to ignore the first part, and connect the chars again in order to check them
if(Character.isHighSurrogate(normalCharacter)) {
continue;
}
// in this case we already have unicode, this can either come from the multiple char replacement
// or because we already got unicode to begin with (multi char only), in that case, we also do a duplicate check
// and add it directly
if(Character.isLowSurrogate(normalCharacter)) {
String usedUnicode = split[i - 1] + charAsString;
if(!usedReplacements.contains(usedUnicode) || allowDuplicates) {
usedReplacements.add(usedUnicode);
result.add(usedUnicode);
}
continue;
}
if(replacedCombos.contains(charAsString) && (!usedReplacements.contains(charAsString) || allowDuplicates)) {
usedReplacements.add(charAsString);
result.add(charAsString);
continue;
}
// reject any other character, as the ones we can deal with
if (!this.reactMapping.getSingle().containsKey(charAsString)) {
log.info("Cannot find mapping. Not replacing with emote.");
continue;
}
List<String> listToUse = this.reactMapping.getSingle().get(charAsString);
boolean foundReplacement = false;
for (String replacementChar : listToUse) {
if (!usedReplacements.contains(replacementChar) || allowDuplicates) {
result.add(replacementChar);
usedReplacements.add(replacementChar);
foundReplacement = true;
break;
}
}
if (!foundReplacement) {
throw new ReactDuplicateCharacterException();
}
}
log.debug("We used {} replacements for a string of length {}.", usedReplacements.size(), text.length());
return result;
}
@Override
public String convertTextToEmojisAsString(String text, boolean allowDuplicates) {
return String.join("", convertTextToEmojis(text, allowDuplicates));
}
@PostConstruct
public void postConstruct() {
try {
JsonReader reader = new JsonReader(new InputStreamReader(reactMappingSource.getInputStream()));
this.reactMapping = gson.fromJson(reader, ReactMapping.class);
this.reactMapping.populateKeys();
log.info("Loaded {} single replacement mappings.", this.reactMapping.getSingle().size());
log.info("Loaded {} combo replacements.", this.reactMapping.getCombination().size());
} catch (IOException e) {
log.error("Failed to load react bindings.", e);
}
}
}

View File

@@ -3,8 +3,8 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="entertainment-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="entertainmentModule" value="(SELECT id FROM module WHERE name = 'entertainment')"/>
<property name="entertainmentFeature" value="(SELECT id FROM feature WHERE key = 'entertainment')"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="module.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="entertainment_feature-insertion">
<insert tableName="feature">
<column name="key" value="entertainment"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="entertainment-module-insertion">
<insert tableName="module">
<column name="name" value="entertainment"/>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="entertainment-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,20 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="entertainmentModule" value="(SELECT id FROM module WHERE name = 'entertainment')"/>
<property name="entertainmentFeature" value="(SELECT id FROM feature WHERE key = 'entertainment')"/>
<changeSet author="Sheldan" id="mock-command">
<insert tableName="command">
<column name="name" value="mock"/>
<column name="module_id" valueComputed="${entertainmentModule}"/>
<column name="feature_id" valueComputed="${entertainmentFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="entertainment-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,20 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="entertainmentModule" value="(SELECT id FROM module WHERE name = 'entertainment')"/>
<property name="entertainmentFeature" value="(SELECT id FROM feature WHERE key = 'entertainment')"/>
<changeSet author="Sheldan" id="react-command">
<insert tableName="command">
<column name="name" value="react"/>
<column name="module_id" valueComputed="${entertainmentModule}"/>
<column name="feature_id" valueComputed="${entertainmentFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -257,6 +257,7 @@
<xsd:attributeGroup name="changeLogAttributes">
<xsd:attribute name="logicalFilePath" type="xsd:string"/>
<xsd:attribute name="context" type="xsd:string"/>
<xsd:attribute name="changeLogId" type="xsd:string"/>
<xsd:attribute name="objectQuotingStrategy" type="objectQuotingStrategy" default="LEGACY"/>
</xsd:attributeGroup>
@@ -277,11 +278,12 @@
<xsd:attribute name="created" type="xsd:string"/>
<xsd:attribute name="runOrder" type="xsd:string"/>
<xsd:attribute name="ignore" type="booleanExp"/>
<xsd:attribute name="runWith" type="xsd:string" />
</xsd:attributeGroup>
<!-- Attributes for changes -->
<xsd:attributeGroup name="changeAttributes">
<xsd:anyAttribute namespace="##any" processContents="lax"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:attributeGroup>
<!-- Attributes for constraints -->
@@ -306,7 +308,7 @@
<xsd:attribute name="validateNullable" type="booleanExp"/>
<xsd:attribute name="validateUnique" type="booleanExp"/>
<xsd:attribute name="validatePrimaryKey" type="booleanExp"/>
<xsd:attribute name="validateForeignKey " type="booleanExp"/>
<xsd:attribute name="validateForeignKey" type="booleanExp"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="column">
@@ -420,9 +422,10 @@
<xsd:attribute name="incrementBy" type="xsd:string"/>
<xsd:attribute name="maxValue" type="xsd:string"/>
<xsd:attribute name="minValue" type="xsd:string"/>
<xsd:attribute name="ordered" type="booleanExp"/>
<xsd:attribute name="ordered" type="xsd:string"/>
<xsd:attribute name="cacheSize" type="xsd:string"/>
<xsd:attribute name="cycle" type="booleanExp">
<xsd:attribute name="dataType" type="xsd:string" />
<xsd:attribute name="cycle" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
true for a cycling sequence, false for a non-cycling sequence.
@@ -481,11 +484,15 @@
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="constraintName" type="xsd:string"/>
<xsd:attribute name="dropIndex" type="booleanExp"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="addUniqueConstraint">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="columnNames" type="xsd:string"
@@ -616,6 +623,7 @@
<xsd:attribute name="header" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="allowUpdate" type="booleanExp"/>
<xsd:attribute name="defaultValue" type="xsd:string"/>
<xsd:attribute name="defaultValueNumeric" type="xsd:string"/>
<xsd:attribute name="defaultValueDate" type="xsd:string"/>
@@ -919,6 +927,7 @@
<xsd:attribute name="schemaName" type="xsd:string"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="columnName" type="xsd:string" use="required"/>
<xsd:attribute name="columnDataType" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -957,6 +966,7 @@
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="tablespace" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1124,7 +1134,7 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="tag" type="xsd:string" use="required"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1226,7 +1236,6 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="sequenceAttributes"/>
<xsd:attribute name="dataType" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -1283,7 +1292,7 @@
</xsd:sequence>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="class" type="xsd:string" use="required"/>
<xsd:anyAttribute processContents="lax" />
</xsd:complexType>
</xsd:element>
@@ -1374,4 +1383,4 @@
</xsd:sequence>
</xsd:group>
</xsd:schema>
</xsd:schema>

View File

@@ -3,8 +3,10 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.0-entertainment/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.8-entertainment/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.9-entertainment/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,281 @@
{
"source": "https://github.com/TrustyJAID/Trusty-cogs/blob/master/fun/constants.py with additions",
"single": {
"a": [
"🇦",
"🅰",
"🍙",
"🔼",
"4⃣",
"🇱🇨",
"🎄",
"🌲",
"🖇️",
"🔼"
],
"b": [
"🇧",
"🅱",
"8⃣"
],
"c": [
"🇨",
"🗜"
],
"d": [
"🇩",
"↩"
],
"e": [
"🇪",
"3⃣",
"📧",
"💶"
],
"f": [
"🇫",
"🎏",
"🚩",
"🏳️️",
"🏴",
"🏁"
],
"g": [
"🇬",
"🗜",
"6⃣",
"9⃣",
"⛽"
],
"h": [
"🇭",
"♓",
"🏩",
"⛩️",
"🪜"
],
"i": [
"🇮",
"",
"🚹",
"1⃣",
"📍"
],
"j": [
"🇯",
"🗾"
],
"k": [
"🇰",
"🎋"
],
"l": [
"🇱",
"1⃣",
"🇮",
"👢",
"💷"
],
"m": [
"🇲",
"Ⓜ",
"📉"
],
"n": [
"🇳",
"♑",
"🎵"
],
"o": [
"🇴",
"🅾",
"0⃣",
"⭕",
"🔘",
"⏺",
"⚪",
"⚫",
"🔵",
"🔴",
"💫",
"⚽",
"🏀",
"⚾",
"🥎",
"🎾",
"🏐",
"💿",
"📀",
"🧭",
"☯️"
],
"p": [
"🇵",
"🅿",
"🚏"
],
"q": [
"🇶",
"♌"
],
"r": [
"🇷",
"🌱"
],
"s": [
"🇸",
"💲",
"5⃣",
"⚡",
"💰",
"💵"
],
"t": [
"🇹",
"✝",
"",
"🎚",
"🌴",
"7⃣"
],
"u": [
"🇺",
"⛎",
"🐉"
],
"v": [
"🇻",
"♈",
"☑"
],
"w": [
"🇼",
"〰",
"📈"
],
"x": [
"🇽",
"❎",
"✖",
"❌",
"⚒",
"🏴‍☠",
"✂️️"
],
"y": [
"🇾",
"✌",
"💴"
],
"z": [
"🇿",
"2⃣"
],
"0": [
"0⃣",
"🅾",
"0⃣",
"⭕",
"🔘",
"⏺",
"⚪",
"⚫",
"🔵",
"🔴",
"💫",
"⚽",
"🏀",
"⚾",
"🥎",
"🎾",
"🏐",
"💿",
"📀",
"🧭",
"☯️"
],
"1": [
"1⃣",
"🇮"
],
"2": [
"2⃣",
"🇿"
],
"3": [
"3⃣"
],
"4": [
"4⃣"
],
"5": [
"5⃣",
"🇸",
"💲",
"⚡"
],
"6": [
"6⃣"
],
"7": [
"7⃣"
],
"8": [
"8⃣",
"🎱",
"🇧",
"🅱"
],
"9": [
"9⃣"
],
"?": [
"❓"
],
"!": [
"❗",
"❕",
"⚠",
"❣"
]
},
"combination": {
"abcd": "🔠",
"1234": "🔢",
"cool": "🆒",
"back": "🔙",
"777": "🎰",
"soon": "🔜",
"free": "🆓",
"end": "🔚",
"top": "🔝",
"abc": "🔤",
"atm": "🏧",
"new": "🆕",
"sos": "🆘",
"100": "💯",
"loo": "💯",
"zzz": "💤",
"...": "💬",
"ng": "🆖",
"id": "🆔",
"vs": "🆚",
"wc": "🚾",
"ab": "🆎",
"cl": "🆑",
"ok": "🆗",
"up": "🆙",
"10": "🔟",
"24": "🏪",
"11": "⏸",
"ll": "⏸",
"ii": "⏸",
"18": "🏪",
"tm": "™",
"on": "🔛",
"oo": "🈁",
"!?": "⁉",
"!!": "‼",
"17": "📅"
}
}

View File

@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.RollResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -1,21 +1,34 @@
package dev.sheldan.abstracto.entertainment.service;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
import dev.sheldan.abstracto.entertainment.model.ReactMapping;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.io.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Reader;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@@ -29,6 +42,19 @@ public class EntertainmentServiceBeanTest {
@Mock
private ConfigService configService;
// requires the org.mockito.plugins.MockMaker file
@Mock
private Gson gson;
@Mock
private Resource resource;
@Mock
private Member member;
@Mock
private Member secondMember;
private static final String INPUT_TEXT = "input";
private static final int RANDOM_VALUE = 0;
@@ -94,4 +120,99 @@ public class EntertainmentServiceBeanTest {
Assert.assertEquals(choices.get(0), choiceTaken);
}
@Test
public void testMocking() {
Assert.assertEquals("AsDf", testUnit.createMockText("asdf", member, secondMember));
}
@Test
public void testMockingUpperCase() {
Assert.assertEquals("AsDf", testUnit.createMockText("ASDF", member, secondMember));
}
@Test
public void testMockingNull() {
Assert.assertEquals("", testUnit.createMockText(null, member, secondMember));
}
@Test
public void testConvertTextToEmojis() throws IOException {
setupMappings();
Assert.assertEquals("bceg", testUnit.convertTextToEmojisAsString("asdf", false));
}
@Test(expected = ReactDuplicateCharacterException.class)
public void testConvertTextToEmojisDuplicateReplacement() throws IOException {
setupMappings();
testUnit.convertTextToEmojisAsString("aa", false);
}
@Test
public void testConvertTextToEmojisNoReplacementFound() throws IOException {
setupMappings();
Assert.assertEquals("", testUnit.convertTextToEmojisAsString("e", false));
}
@Test
public void testConvertTextToEmojisNullInput() throws IOException {
setupMappings();
Assert.assertEquals("", testUnit.convertTextToEmojisAsString(null, false));
}
@Test
public void testConvertTextToEmojisDoubleUnicodePassThrough() throws IOException {
setupMappings();
Assert.assertEquals("\uD83C\uDD98", testUnit.convertTextToEmojisAsString("\uD83C\uDD98", false));
}
@Test
public void testConvertTextToEmojisDuplicate() throws IOException {
setupMappings();
Assert.assertEquals("bb", testUnit.convertTextToEmojisAsString("aa", true));
}
@Test
public void testConvertTextToEmojisCombinations() throws IOException {
setupMappings();
Assert.assertEquals("\uD83C\uDD98", testUnit.convertTextToEmojisAsString("kk", true));
}
@Test
public void testConvertTextToEmojisCombinationWithNormalText() throws IOException {
setupMappings();
Assert.assertEquals("\uD83C\uDD98l", testUnit.convertTextToEmojisAsString("kkk", false));
}
@Test
public void testConvertTextToEmojisCombinationWithNormalTextMixed() throws IOException {
setupMappings();
Assert.assertEquals("\uD83C\uDD98lm", testUnit.convertTextToEmojisAsString("kkkk", false));
}
@Test
public void testConvertTextToEmojisCombinationDuplicates() throws IOException {
setupMappings();
Assert.assertEquals("\uD83C\uDD98\uD83C\uDD98", testUnit.convertTextToEmojisAsString("kkkk", true));
}
private void setupMappings() throws IOException {
ReactMapping mapping = Mockito.mock(ReactMapping.class);
HashMap<String, List<String>> singleMappings = new HashMap<>();
singleMappings.put("a", Arrays.asList("b"));
singleMappings.put("s", Arrays.asList("c"));
singleMappings.put("d", Arrays.asList("e"));
singleMappings.put("f", Arrays.asList("g"));
singleMappings.put("k", Arrays.asList("l", "m"));
when(resource.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[]{1}));
when(mapping.getSingle()).thenReturn(singleMappings);
HashMap<String, String> combinations = new HashMap<>();
combinations.put("kk", "\uD83C\uDD98");
when(mapping.getCombination()).thenReturn(combinations);
TreeSet<String> combinationKeys = new TreeSet<>();
combinationKeys.add("kk");
when(mapping.getCombinationKeys()).thenReturn(combinationKeys);
when(gson.fromJson(any(JsonReader.class), eq(ReactMapping.class))).thenReturn(mapping);
testUnit.postConstruct();
}
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.entertainment.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ReactDuplicateCharacterException extends AbstractoRunTimeException implements Templatable {
public ReactDuplicateCharacterException() {
super("Could not replace all characters to be duplicate free.");
}
@Override
public String getTemplateName() {
return "react_duplicate_character_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.entertainment.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ReactTooManyReactionsException extends AbstractoRunTimeException implements Templatable {
public ReactTooManyReactionsException() {
super("Adding reactions would lead to too many reactions.");
}
@Override
public String getTemplateName() {
return "react_too_many_reactions_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.entertainment.model;
import lombok.*;
import java.util.*;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ReactMapping {
@Builder.Default
private HashMap<String, List<String>> single = new HashMap<>();
@Builder.Default
private HashMap<String, String> combination = new HashMap<>();
@Builder.Default
private SortedSet<String> combinationKeys = new TreeSet<>((o1, o2) -> {
if(o2.length() == o1.length()) {
return o2.compareTo(o1);
} else {
return Integer.compare(o2.length(), o1.length());
}
});
@Builder.Default
private Set<String> combinationReplacements = new HashSet<>();
public void populateKeys() {
combinationKeys.addAll(combination.keySet());
combinationKeys.forEach(s -> combinationReplacements.add(this.combination.get(s)));
}
}

View File

@@ -1,4 +1,4 @@
package dev.sheldan.abstracto.entertainment.model;
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package dev.sheldan.abstracto.entertainment.model;
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package dev.sheldan.abstracto.entertainment.model;
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter
@Setter
@SuperBuilder
public class MockResponseModel extends SlimUserInitiatedServerContext {
private String originalText;
private String mockingText;
}

View File

@@ -1,4 +1,4 @@
package dev.sheldan.abstracto.entertainment.model;
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package dev.sheldan.abstracto.entertainment.model;
package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter;

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.entertainment.service;
import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException;
import net.dv8tion.jda.api.entities.Member;
import java.util.List;
@@ -10,4 +11,65 @@ public interface EntertainmentService {
Integer calculateRollResult(Integer low, Integer high);
boolean executeRoulette(Member memberExecuting);
String takeChoice(List<String> choices, Member memberExecuting);
String createMockText(String text, Member memberExecuting, Member mockedUser);
/**
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
* characters as a list. If the given text is null, an empty list will be returned. This method will actively try
* to avoid duplicates, and try to use alternatives, and throw an exception in case it was not possible to return unique values.
* The size of the list might not be equal to the length of the provided string, because sometimes multiple
* characters are combined into one unicode char.
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
* in case there too many duplicated characters
* @param text The text to convert
* @return A {@link List} of unicode characters, represented as strings, which look similar to the individual characters
* from the text
*/
List<String> convertTextToEmojis(String text);
/**
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
* characters as a string. If the given text is null, an empty string will be returned. This method will actively try
* to avoid duplicates, and try to use alternatives, and throw an exception in case it was not possible to return unique values.
* The length of the string might not be equal to the length of the provided string, because sometimes multiple
* characters are combined into one unicode char.
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
* in case there too many duplicated characters
* @param text The text to convert
* @return A string of unicode characters which look similar to the individual characters from the text
*/
String convertTextToEmojisAString(String text);
/**
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
* characters as a list. If the given text is null, an empty list will be returned. This method will actively try
* to avoid duplicates (if requested), and try to use alternatives, and throw an exception in case it was not possible
* to return unique values. In case duplicates are allowed, the first possible replacement value will be used,
* leading to all 1:1 replacements being of the same character.
* The size of the list might not be equal to the length of the provided string, because sometimes multiple
* characters are combined into one unicode char.
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
* in case there too many duplicated characters
* @param text The text to convert
* @param allowDuplicates Whether or not to allow duplicates
* @return A list of characters, represented as strings, which look similar to the individual characters
* from the text, possible with duplicates, if requested
*/
List<String> convertTextToEmojis(String text, boolean allowDuplicates);
/**
* Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched
* characters as a string. If the given text is null, an empty string will be returned. This method will actively try
* to avoid duplicates (if requested), and try to use alternatives, and throw an exception in case it was not possible
* to return unique values. In case duplicates are allowed, the first possible replacement value will be used,
* leading to all 1:1 replacements being of the same character.
* The length of the string might not be equal to the length of the provided string, because sometimes multiple
* characters are combined into one unicode char.
* @throws ReactDuplicateCharacterException In case it was not possible to replace all text with appropriate unicode
* in case there too many duplicated characters
* @param text The text to convert
* @param allowDuplicates Whether or not to allow duplicates
* @return A string of unicode characters which look similar to the individual characters from the text
*/
String convertTextToEmojisAsString(String text, boolean allowDuplicates);
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.2.6</version>
<version>1.2.15</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -33,7 +33,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* Shows the experience gain information of the top 10 users in the server, or if a page number is provided as a parameter, only the members which are on this page.
@@ -69,18 +68,18 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
AServer server = serverManagementService.loadServer(commandContext.getGuild());
LeaderBoard leaderBoard = userExperienceService.findLeaderBoardData(server, page);
LeaderBoardModel leaderBoardModel = (LeaderBoardModel) ContextConverter.slimFromCommandContext(commandContext, LeaderBoardModel.class);
List<CompletableFuture<LeaderBoardEntryModel>> futures = new ArrayList<>();
List<CompletableFuture<LeaderBoardEntryModel>> completableFutures = converter.fromLeaderBoard(leaderBoard);
futures.addAll(completableFutures);
List<CompletableFuture> futures = new ArrayList<>();
CompletableFuture<List<LeaderBoardEntryModel>> completableFutures = converter.fromLeaderBoard(leaderBoard);
futures.add(completableFutures);
log.info("Rendering leaderboard for page {} in server {} for user {}.", page, commandContext.getAuthor().getId(), commandContext.getGuild().getId());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
CompletableFuture<LeaderBoardEntryModel> userRankFuture = converter.fromLeaderBoardEntry(userRank);
CompletableFuture<List<LeaderBoardEntryModel>> userRankFuture = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
futures.add(userRankFuture);
return FutureUtils.toSingleFutureGeneric(futures).thenCompose(aVoid -> {
List<LeaderBoardEntryModel> finalModels = completableFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
return FutureUtils.toSingleFuture(futures).thenCompose(aVoid -> {
List<LeaderBoardEntryModel> finalModels = completableFutures.join();
leaderBoardModel.setUserExperiences(finalModels);
leaderBoardModel.setUserExecuting(userRankFuture.join());
leaderBoardModel.setUserExecuting(userRankFuture.join().get(0));
MessageToSend messageToSend = templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel, commandContext.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()));
}).thenApply(aVoid -> CommandResult.fromIgnored());

View File

@@ -0,0 +1,73 @@
package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.model.template.LevelRole;
import dev.sheldan.abstracto.experience.model.template.LevelRolesModel;
import dev.sheldan.abstracto.experience.service.ExperienceRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Component
public class LevelRoles extends AbstractConditionableCommand {
@Autowired
private ExperienceRoleService experienceRoleService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private ChannelService channelService;
private static final String LEVEL_ROLES_TEMPLATE_KEY = "levelRoles_response";
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild());
List<LevelRole> levelRoles = experienceRoleService.loadLevelRoleConfigForServer(server);
levelRoles = levelRoles.stream().sorted(Comparator.comparingInt(LevelRole::getLevel).reversed()).collect(Collectors.toList());
LevelRolesModel model = LevelRolesModel
.builder()
.levelRoles(levelRoles)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(LEVEL_ROLES_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("levelRoles")
.module(ExperienceModuleDefinition.EXPERIENCE)
.async(true)
.templated(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return ExperienceFeatureDefinition.EXPERIENCE;
}
}

View File

@@ -6,7 +6,6 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
@@ -24,11 +23,13 @@ import dev.sheldan.abstracto.experience.service.management.UserExperienceManagem
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -66,12 +67,17 @@ public class Rank extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
RankModel rankModel = (RankModel) ContextConverter.slimFromCommandContext(commandContext, RankModel.class);
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
List<Object> parameters = commandContext.getParameters().getParameters();
Member parameter = !parameters.isEmpty() ? (Member) parameters.get(0) : commandContext.getAuthor();
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(parameter);
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
CompletableFuture<LeaderBoardEntryModel> future = converter.fromLeaderBoardEntry(userRank);
CompletableFuture<List<LeaderBoardEntryModel>> future = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
RankModel rankModel = RankModel
.builder()
.member(parameter)
.build();
return future.thenCompose(leaderBoardEntryModel ->
self.renderAndSendRank(commandContext, rankModel, leaderBoardEntryModel)
self.renderAndSendRank(commandContext, rankModel, leaderBoardEntryModel.get(0))
).thenApply(result -> CommandResult.fromIgnored());
}
@@ -89,6 +95,7 @@ public class Rank extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("member").templated(true).type(Member.class).optional(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("rank")

View File

@@ -10,12 +10,16 @@ import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.exception.ExperienceRoleNotFoundException;
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
import dev.sheldan.abstracto.experience.service.ExperienceRoleService;
import dev.sheldan.abstracto.experience.service.management.ExperienceRoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
/**
@@ -31,13 +35,20 @@ public class UnSetExpRole extends AbstractConditionableCommand {
@Autowired
private RoleManagementService roleManagementService;
@Autowired
private ExperienceRoleManagementService experienceRoleManagementService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
ARole role = (ARole) commandContext.getParameters().getParameters().get(0);
ARole actualRole = roleManagementService.findRole(role.getId());
// do not check for the existence of the role, because if the role was deleted, users should be able
// to get rid of it in the configuration
return experienceRoleService.unsetRole(actualRole, commandContext.getChannel().getIdLong())
Optional<AExperienceRole> experienceRole = experienceRoleManagementService.getRoleInServerOptional(actualRole);
if(!experienceRole.isPresent()) {
throw new ExperienceRoleNotFoundException();
}
return experienceRoleService.unsetRoles(actualRole, commandContext.getChannel().getIdLong())
.thenApply(aVoid -> CommandResult.fromSuccess());
}

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.experience.converter;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.experience.model.LeaderBoard;
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
@@ -11,11 +10,14 @@ import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Converter used to convert from {@link LeaderBoard leaderBoard} to a list of {@link LeaderBoardEntryModel leaderBoardEntryModels}
@@ -40,40 +42,36 @@ public class LeaderBoardModelConverter {
* @return The list of {@link LeaderBoardEntryModel leaderboarEntryModels} which contain the fully fledged information provided to the
* leader board template
*/
public List<CompletableFuture<LeaderBoardEntryModel>> fromLeaderBoard(LeaderBoard leaderBoard) {
List<CompletableFuture<LeaderBoardEntryModel>> models = new ArrayList<>();
log.trace("Converting {} entries to a list of leaderboard entries.", leaderBoard.getEntries().size());
leaderBoard.getEntries().forEach(leaderBoardEntry -> {
CompletableFuture<LeaderBoardEntryModel> entry = fromLeaderBoardEntry(leaderBoardEntry);
models.add(entry);
public CompletableFuture<List<LeaderBoardEntryModel>> fromLeaderBoard(LeaderBoard leaderBoard) {
log.debug("Converting {} entries to a list of leaderboard entries.", leaderBoard.getEntries().size());
return fromLeaderBoardEntry(leaderBoard.getEntries());
}
public CompletableFuture<List<LeaderBoardEntryModel>> fromLeaderBoardEntry(List<LeaderBoardEntry> leaderBoardEntries) {
List<Long> userIds = new ArrayList<>();
Long serverId = leaderBoardEntries.get(0).getExperience().getServer().getId();
Map<Long, LeaderBoardEntryModel> models = leaderBoardEntries
.stream()
.map(leaderBoardEntry -> {
AUserExperience experience = leaderBoardEntry.getExperience();
Long userId = experience.getUser().getUserReference().getId();
userIds.add(userId);
return LeaderBoardEntryModel
.builder()
.userId(userId)
.experience(experience.getExperience())
.messageCount(experience.getMessageCount())
.level(experience.getLevelOrDefault())
.rank(leaderBoardEntry.getRank())
.build();
})
.collect(Collectors.toMap(LeaderBoardEntryModel::getUserId, Function.identity()));
return memberService.getMembersInServerAsync(serverId, userIds).thenApply(members -> {
members.forEach(member -> models.get(member.getIdLong()).setMember(member));
return new ArrayList<>(models.values())
.stream()
.sorted(Comparator.comparing(LeaderBoardEntryModel::getRank)).
collect(Collectors.toList());
});
return models;
}
/**
* Converts the given {@link LeaderBoardEntry entry} to a {@link LeaderBoardEntryModel model}, which provides a reference to the
* {@link Member member} object of the given {@link AUserInAServer user} for convenience in the template
* @param leaderBoardEntry The {@link LeaderBoardEntry entry} to be converted
* @return The {@link LeaderBoardEntryModel model} accompanied with the {@link Member member} reference, might be null, if the
* user left the guild
*/
public CompletableFuture<LeaderBoardEntryModel> fromLeaderBoardEntry(LeaderBoardEntry leaderBoardEntry) {
AUserInAServer entryUser = leaderBoardEntry.getExperience().getUser();
Long userInServerId = leaderBoardEntry.getExperience().getUser().getUserInServerId();
Integer rank = leaderBoardEntry.getRank();
return memberService.getMemberInServerAsync(entryUser.getServerReference().getId(), entryUser.getUserReference().getId())
.thenApply(member -> self.buildLeaderBoardModel(userInServerId, member, rank))
.exceptionally(throwable -> self.buildLeaderBoardModel(userInServerId, null, rank));
}
@Transactional
public LeaderBoardEntryModel buildLeaderBoardModel(Long userInServerId, Member member, Integer rank) {
AUserExperience experience = userExperienceManagementService.findByUserInServerId(userInServerId);
return LeaderBoardEntryModel
.builder()
.experience(experience)
.member(member)
.rank(rank)
.build();
}
}

View File

@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -29,9 +30,17 @@ public class ExperienceTrackerListener implements AsyncMessageReceivedListener {
@Override
public DefaultListenerResult execute(MessageReceivedModel model) {
AUserInAServer cause = userInServerManagementService.loadOrCreateUser(model.getServerId(), model.getMessage().getAuthor().getIdLong());
userExperienceService.addExperience(cause);
return DefaultListenerResult.PROCESSED;
Message message = model.getMessage();
if(!message.isFromGuild() || message.isWebhookMessage() || message.getType().isSystem() || message.getAuthor().isBot()) {
return DefaultListenerResult.IGNORED;
}
if(userExperienceService.experienceGainEnabledInChannel(message.getChannel())) {
AUserInAServer cause = userInServerManagementService.loadOrCreateUser(model.getServerId(), model.getMessage().getAuthor().getIdLong());
userExperienceService.addExperience(cause);
return DefaultListenerResult.PROCESSED;
} else {
return DefaultListenerResult.IGNORED;
}
}
@Override

View File

@@ -16,6 +16,8 @@ import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* If a {@link Member member} joins, this {@link JoinListener listener} retrieves the previously stored {@link AUserExperience experience} and gives the
* member the necessary {@link net.dv8tion.jda.api.entities.Role role} according to the current configuration, if any
@@ -36,10 +38,10 @@ public class JoiningUserRoleListener implements AsyncJoinListener {
@Override
public DefaultListenerResult execute(MemberJoinModel model) {
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(model.getServerId(), model.getJoiningUser().getUserId());
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
if(userExperience != null) {
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServer.getUserInServerId());
if(userExperienceOptional.isPresent()) {
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", model.getJoiningUser().getUserId(), model.getServerId());
userExperienceService.syncForSingleUser(userExperience).thenAccept(result ->
userExperienceService.syncForSingleUser(userExperienceOptional.get()).thenAccept(result ->
log.info("Finished re-assigning experience for re-joining user {} in server {}.", model.getJoiningUser().getUserId(), model.getServerId())
);
} else {

View File

@@ -1,18 +1,13 @@
package dev.sheldan.abstracto.experience.service;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.models.property.SystemConfigProperty;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.*;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureConfig;
import dev.sheldan.abstracto.experience.exception.NoExperienceTrackedException;
import dev.sheldan.abstracto.experience.model.*;
import dev.sheldan.abstracto.experience.model.database.*;
import dev.sheldan.abstracto.experience.model.template.UserSyncStatusModel;
@@ -25,6 +20,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -81,6 +77,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private ChannelGroupService channelGroupService;
@Autowired
private DefaultConfigManagementService defaultConfigManagementService;
@@ -93,24 +92,26 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
try {
Long minute = Instant.now().getEpochSecond() / 60;
Map<Long, List<ServerExperience>> runtimeExperience = runTimeExperienceService.getRuntimeExperience();
Long serverId = userInAServer.getServerReference().getId();
Long userInServerId = userInAServer.getUserInServerId();
if(runtimeExperience.containsKey(minute)) {
log.trace("Minute {} already tracked, adding user {} in server {}.",
minute, userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
log.debug("Minute {} already tracked, adding user {} in server {}.",
minute, userInAServer.getUserReference().getId(), serverId);
List<ServerExperience> existing = runtimeExperience.get(minute);
for (ServerExperience server : existing) {
if (server.getServerId().equals(userInAServer.getServerReference().getId()) && server.getUserInServerIds().stream().noneMatch(userInAServer1 -> userInAServer.getUserInServerId().equals(userInAServer1))) {
server.getUserInServerIds().add(userInAServer.getUserInServerId());
if (server.getServerId().equals(serverId) && server.getUserInServerIds().stream().noneMatch(userInServerId::equals)) {
server.getUserInServerIds().add(userInServerId);
break;
}
}
} else {
log.trace("Minute {} did not exist yet. Creating new entry for user {} in server {}.", minute, userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
log.debug("Minute {} did not exist yet. Creating new entry for user {} in server {}.", minute, userInAServer.getUserReference().getId(), serverId);
ServerExperience serverExperience = ServerExperience
.builder()
.serverId(userInAServer.getServerReference().getId())
.serverId(serverId)
.build();
serverExperience.getUserInServerIds().add(userInAServer.getUserInServerId());
serverExperience.getUserInServerIds().add(userInServerId);
runtimeExperience.put(minute, new ArrayList<>(Arrays.asList(serverExperience)));
}
} finally {
@@ -124,13 +125,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
AExperienceLevel lastLevel = levels.get(0);
for (AExperienceLevel level : levels) {
if(level.getExperienceNeeded() >= experienceCount) {
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
log.debug("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel;
} else {
lastLevel = level;
}
}
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
log.debug("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel;
}
@@ -152,34 +153,57 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
public CompletableFuture<Void> handleExperienceGain(List<ServerExperience> servers) {
List<ExperienceGainResult> resultFutures = new ArrayList<>();
List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>();
CompletableFuture<Void> experienceFuture = new CompletableFuture<>();
// TODO what if there are a lot in here...., transaction size etc
servers.forEach(serverExp -> {
List<CompletableFuture<Member>> memberFutures = new ArrayList<>();
serverExp.getUserInServerIds().forEach(userInAServerId -> {
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(userInAServerId);
CompletableFuture<Member> memberFuture = memberService.getMemberInServerAsync(userInAServer);
memberFutures.add(memberFuture);
});
FutureUtils.toSingleFutureGeneric(memberFutures).whenComplete((unused, throwable) -> {
self.updateFoundMembers(memberFutures, serverExp.getServerId(), resultFutures, futures);
experienceFuture.complete(null);
});
});
return experienceFuture
.thenCompose(unused -> FutureUtils.toSingleFutureGeneric(futures))
.whenComplete((unused, throwable) -> self.persistExperienceChanges(resultFutures));
}
@Transactional
public void updateFoundMembers(List<CompletableFuture<Member>> memberFutures, Long serverId, List<ExperienceGainResult> resultFutures, List<CompletableFuture<RoleCalculationResult>> futures) {
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
SystemConfigProperty defaultExpMultiplier = defaultConfigManagementService.getDefaultConfig(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY);
SystemConfigProperty defaultMinExp = defaultConfigManagementService.getDefaultConfig(ExperienceFeatureConfig.MIN_EXP_KEY);
SystemConfigProperty defaultMaxExp = defaultConfigManagementService.getDefaultConfig(ExperienceFeatureConfig.MAX_EXP_KEY);
// TODO what if there are a lot in here...., transaction size etc
servers.forEach(serverExp -> {
AServer server = serverManagementService.loadOrCreate(serverExp.getServerId());
log.info("Handling {} experience for server {}", serverExp.getUserInServerIds().size(), serverExp.getServerId());
int minExp = configService.getLongValue(ExperienceFeatureConfig.MIN_EXP_KEY, serverExp.getServerId(), defaultMinExp.getLongValue()).intValue();
int maxExp = configService.getLongValue(ExperienceFeatureConfig.MAX_EXP_KEY, serverExp.getServerId(), defaultMaxExp.getLongValue()).intValue();
Double multiplier = configService.getDoubleValue(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverExp.getServerId(), defaultExpMultiplier.getDoubleValue());
PrimitiveIterator.OfInt iterator = new Random().ints(serverExp.getUserInServerIds().size(), minExp, maxExp + 1).iterator();
levels.sort(Comparator.comparing(AExperienceLevel::getExperienceNeeded));
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
List<ADisabledExpRole> disabledExpRoles = disabledExpRoleManagementService.getDisabledRolesForServer(server);
List<ARole> disabledRoles = disabledExpRoles.stream().map(ADisabledExpRole::getRole).collect(Collectors.toList());
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
serverExp.getUserInServerIds().forEach(userInAServerId -> {
AServer server = serverManagementService.loadOrCreate(serverId);
int minExp = configService.getLongValue(ExperienceFeatureConfig.MIN_EXP_KEY, serverId, defaultMinExp.getLongValue()).intValue();
int maxExp = configService.getLongValue(ExperienceFeatureConfig.MAX_EXP_KEY, serverId, defaultMaxExp.getLongValue()).intValue();
Double multiplier = configService.getDoubleValue(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverId, defaultExpMultiplier.getDoubleValue());
PrimitiveIterator.OfInt iterator = new Random().ints(memberFutures.size(), minExp, maxExp + 1).iterator();
levels.sort(Comparator.comparing(AExperienceLevel::getExperienceNeeded));
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
List<ADisabledExpRole> disabledExpRoles = disabledExpRoleManagementService.getDisabledRolesForServer(server);
List<ARole> disabledRoles = disabledExpRoles.stream().map(ADisabledExpRole::getRole).collect(Collectors.toList());
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
log.info("Handling {} experiences for server {}. Using {} roles.", memberFutures.size(), serverId, roles.size());
memberFutures.forEach(future -> {
if(!future.isCompletedExceptionally()) {
Integer gainedExperience = iterator.next();
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(userInAServerId);
gainedExperience = (int) Math.floor(gainedExperience * multiplier);
Member member = memberService.getMemberInServer(userInAServer);
if(member != null && !roleService.hasAnyOfTheRoles(member, disabledRoles)) {
log.trace("Handling {}. The user gains {}", userInAServer.getUserReference().getId(), gainedExperience);
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServerId);
Member member = future.join();
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
Long userInServerId = userInAServer.getUserInServerId();
if(!roleService.hasAnyOfTheRoles(member, disabledRoles)) {
log.debug("Handling {}. The user might gain {}.", userInServerId, gainedExperience);
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServer.getUserInServerId());
if(aUserExperienceOptional.isPresent()) {
AUserExperience aUserExperience = aUserExperienceOptional.get();
if(Boolean.FALSE.equals(aUserExperience.getExperienceGainDisabled())) {
log.debug("User {} will gain experience.", userInServerId);
Long newExperienceCount = aUserExperience.getExperience() + gainedExperience.longValue();
AExperienceLevel newLevel = calculateLevel(levels, newExperienceCount);
CompletableFuture<RoleCalculationResult> resultFuture = updateUserRole(aUserExperience, roles, newLevel.getLevel());
@@ -196,7 +220,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
resultFutures.add(calculationResult);
futures.add(resultFuture);
} else {
log.trace("Experience gain was disabled. User did not gain any experience.");
log.debug("Experience gain was disabled. User did not gain any experience.");
}
} else {
log.info("User experience for user {} was not found. Planning to create new instance.", userInAServer.getUserInServerId());
@@ -218,14 +242,10 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
futures.add(resultFuture);
}
} else {
log.trace("User {} has a role which makes the user unable to gain experience or the member could not be found in the server.", userInAServer.getUserInServerId());
log.debug("User {} has a role which makes the user unable to gain experience.", userInAServer.getUserInServerId());
}
});
}
});
return FutureUtils.toSingleFutureGeneric(futures).thenAccept(aVoid ->
self.persistExperienceChanges(resultFutures)
);
}
/**
@@ -240,20 +260,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
* @return A {@link CompletableFuture future} containing the {@link RoleCalculationResult result} of the role calculation, which completes after the user has been awarded the role.
*/
private CompletableFuture<RoleCalculationResult> applyInitialRole(AUserInAServer aUserInAServer, List<AExperienceRole> roles, Integer currentLevel) {
// we are in the process of attributing experience, which means the member should have send a message, therefore is in the case
// if the member is actually _not_ in the guild anymore (would mean, joined, send a message, and left immediately) this check is required
// this is backed by the cache
if(!memberService.isUserInGuild(aUserInAServer)) {
log.trace("User {} is not in server {} anymore. No role calculation done.", aUserInAServer.getUserInServerId(), aUserInAServer.getServerReference().getId());
return CompletableFuture.completedFuture(RoleCalculationResult
.builder()
.userInServerId(aUserInAServer.getUserInServerId())
.experienceRoleId(null)
.build());
}
AExperienceRole role = experienceRoleService.calculateRole(roles, currentLevel);
if(role == null) {
log.trace("No experience role calculated. Applying none to user {} in server {}.",
log.debug("No experience role calculated. Applying none to user {} in server {}.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
return CompletableFuture.completedFuture(RoleCalculationResult
.builder()
@@ -263,7 +272,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
Long experienceRoleId = role.getId();
Long userInServerId = aUserInAServer.getUserInServerId();
log.trace("Applying {} as the first experience role for user {} in server {}.",
log.debug("Applying {} as the first experience role for user {} in server {}.",
experienceRoleId, aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
return roleService.addRoleToUserFuture(aUserInAServer, role.getRole()).thenApply(aVoid -> RoleCalculationResult
.builder()
@@ -281,7 +290,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Transactional
public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) {
// we do have the _value_ of the level, but we require the actual instance
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
Map<Integer, AExperienceLevel> levels = experienceLevelManagementService.getLevelConfigAsMap();
log.info("Storing {} experience gain results.", resultFutures.size());
HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>();
resultFutures.forEach(experienceGainResult -> {
@@ -289,18 +298,20 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
AUserExperience userExperience;
if(experienceGainResult.isCreateUserExperience()) {
userExperience = userExperienceManagementService.createUserInServer(user);
log.info("Creating new experience user {}", experienceGainResult.getUserInServerId());
log.info("Creating new experience user for user in server {}.", experienceGainResult.getUserInServerId());
} else {
userExperience = userExperienceManagementService.findByUserInServerId(experienceGainResult.getUserInServerId());
}
userExperience.setMessageCount(experienceGainResult.getNewMessageCount());
userExperience.setExperience(experienceGainResult.getNewExperience());
// only search the levels if the level changed, or if there is no level currently set
boolean userExperienceHasLevel = userExperience.getCurrentLevel() != null;
if(!userExperienceHasLevel || !userExperience.getCurrentLevel().getLevel().equals(experienceGainResult.getNewLevel())) {
Optional<AExperienceLevel> foundLevel = levels.stream().filter(level -> level.getLevel().equals(experienceGainResult.getNewLevel())).findFirst();
if(foundLevel.isPresent()) {
userExperience.setCurrentLevel(foundLevel.get());
AExperienceLevel currentLevel = userExperience.getCurrentLevel();
boolean userExperienceHasLevel = currentLevel != null;
if(!userExperienceHasLevel || !currentLevel.getLevel().equals(experienceGainResult.getNewLevel())) {
AExperienceLevel foundLevel = levels.get(experienceGainResult.getNewLevel());
if(foundLevel != null) {
log.info("User {} in server {} changed the level. Old level {}. New level {}.", experienceGainResult.getUserInServerId(), experienceGainResult.getServerId(), currentLevel.getLevel(), experienceGainResult.getNewLevel());
userExperience.setCurrentLevel(foundLevel);
} else {
log.warn("User {} was present, but no level matching the calculation result {} could be found.", userExperience.getUser().getUserReference().getId(), experienceGainResult.getNewLevel());
}
@@ -331,15 +342,15 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
.build();
Long userInServerId = user.getUserInServerId();
Long serverId = user.getServerReference().getId();
log.trace("Updating experience role for user {} in server {}", user.getUserReference().getId(), serverId);
log.debug("Updating experience role for user {} in server {}", user.getUserReference().getId(), serverId);
AExperienceRole role = experienceRoleService.calculateRole(roles, currentLevel);
boolean currentlyHasNoExperienceRole = userExperience.getCurrentExperienceRole() == null;
// if calculation results in no role, do not add a role
if(role == null) {
log.trace("User {} in server {} does not have an experience role, according to new calculation.",
log.debug("User {} in server {} does not have an experience role, according to new calculation.",
user.getUserReference().getId(), serverId);
// if the user has a experience role currently, remove it
if(!currentlyHasNoExperienceRole){
if(!currentlyHasNoExperienceRole && !userExperience.getCurrentExperienceRole().getRole().getDeleted()){
return roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole())
.thenApply(returnNullRole);
}
@@ -366,16 +377,17 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
// if the roles changed or
// the user does not have the new target role already
// the user still has the old role
if((!userHasRoleAlready || userHasOldRole)) {
log.info("User {} in server {} gets a new role {} because of experience.", userId, serverId, roleId);
if(!userHasRoleAlready || userHasOldRole) {
CompletableFuture<Void> removalFuture;
if(userHasOldRole && rolesChanged) {
log.info("User {} in server {} loses experience role {}.", userId, serverId, oldUserExperienceRoleId);
removalFuture = roleService.removeRoleFromMemberAsync(member, oldUserExperienceRoleId);
} else {
removalFuture = CompletableFuture.completedFuture(null);
}
CompletableFuture<Void> addRoleFuture;
if(!userHasRoleAlready) {
log.info("User {} in server {} gets a new role {} because of experience.", userId, serverId, roleId);
addRoleFuture = roleService.addRoleToMemberFuture(member, roleId);
} else {
addRoleFuture = CompletableFuture.completedFuture(null);
@@ -393,9 +405,10 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
List<AUserExperience> aUserExperiences = userExperienceManagementService.loadAllUsers(server);
log.info("Found {} users to synchronize", aUserExperiences.size());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
for (int i = 0; i < aUserExperiences.size(); i++) {
AUserExperience userExperience = aUserExperiences.get(i);
log.trace("Synchronizing {} out of {}", i, aUserExperiences.size());
log.info("Synchronizing {} out of {}. User in Server {}.", i, aUserExperiences.size(), userExperience.getUser().getUserInServerId());
results.add(updateUserRole(userExperience, roles, userExperience.getCurrentLevel().getLevel()));
}
return results;
@@ -407,6 +420,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
List<AUserExperience> aUserExperiences = userExperienceManagementService.loadAllUsers(server);
log.info("Found {} users to synchronize", aUserExperiences.size());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
CompletableFutureList<RoleCalculationResult> calculations = executeActionOnUserExperiencesWithFeedBack(aUserExperiences, channel, (AUserExperience experience) -> updateUserRole(experience, roles, experience.getLevelOrDefault()));
return calculations.getMainFuture().thenAccept(aVoid ->
self.syncRolesInStorage(calculations.getObjects())
@@ -415,7 +429,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
/**
* Updates the actually stored experience roles in the database
* @param results The list of {@link RoleCalculationResult} which should be applied
* @param results The list of {@link RoleCalculationResult results} which should be applied
*/
@Transactional
public void syncRolesInStorage(List<RoleCalculationResult> results) {
@@ -424,9 +438,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
if(result != null) {
AUserInAServer user = userInServerManagementService.loadOrCreateUser(result.getUserInServerId());
AUserExperience userExperience = userExperienceManagementService.findUserInServer(user);
log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference().getId(), result.getExperienceRoleId());
log.debug("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference().getId(), result.getExperienceRoleId());
if(result.getExperienceRoleId() != null) {
log.trace("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId());
log.debug("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId());
AExperienceRole role;
if(!experienceRoleHashMap.containsKey(result.getExperienceRoleId())) {
role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId());
@@ -436,13 +450,40 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
userExperience.setCurrentExperienceRole(role);
} else {
log.trace("User experience {} does not get a user experience role.", userExperience.getId());
log.debug("User experience {} does not get a user experience role.", userExperience.getId());
userExperience.setCurrentExperienceRole(null);
}
}
});
}
@Override
public boolean experienceGainEnabledInChannel(MessageChannel messageChannel) {
AChannel channel = channelManagementService.loadChannel(messageChannel.getIdLong());
List<AChannelGroup> channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, EXPERIENCE_GAIN_CHANNEL_GROUP_KEY);
if(!channelGroups.isEmpty()) {
return channelGroups.stream().noneMatch(AChannelGroup::getEnabled);
}
return true;
}
@Override
public AUserExperience createUserExperienceForUser(AUserInAServer aUserInAServer, Long experience, Long messageCount) {
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
levels.sort(Comparator.comparing(AExperienceLevel::getExperienceNeeded));
return createUserExperienceForUser(aUserInAServer, experience, messageCount, levels);
}
@Override
public AUserExperience createUserExperienceForUser(AUserInAServer aUserInAServer, Long experience, Long messageCount, List<AExperienceLevel> levels) {
AExperienceLevel level = calculateLevel(levels, experience);
AUserExperience userExperience = userExperienceManagementService.createUserInServer(aUserInAServer);
userExperience.setCurrentLevel(level);
userExperience.setExperience(experience);
userExperience.setMessageCount(messageCount);
return userExperience;
}
@Override
public CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute) {
List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>();
@@ -452,12 +493,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
int interval = Math.min(Math.max(experiences.size() / 10, 1), 100);
for (int i = 0; i < experiences.size(); i++) {
if((i % interval) == 1) {
log.trace("Updating feedback message with new index {} out of {}", i, experiences.size());
log.info("Updating feedback message with new index {} out of {}.", i, experiences.size());
status = getUserSyncStatusUpdateModel(i, experiences.size(), serverId);
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
}
futures.add(toExecute.apply(experiences.get(i)));
log.trace("Synchronizing {} out of {}", i, experiences.size());
AUserExperience userExperience = experiences.get(i);
futures.add(toExecute.apply(userExperience));
log.debug("Synchronizing {} out of {}. User in server ID {}.", i, experiences.size(), userExperience.getUser().getUserInServerId());
}
status = getUserSyncStatusUpdateModel(experiences.size(), experiences.size(), serverId);
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
@@ -474,8 +516,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Override
public void enableExperienceForUser(AUserInAServer userInAServer) {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
log.info("Enabling experience gain for user {} in server {}.", userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
userExperience.setExperienceGainDisabled(false);
}
@@ -494,8 +536,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Override
public CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience) {
AUserInAServer user = userExperience.getUser();
log.info("Synchronizing for user {} in server {}", user.getUserReference().getId(), user.getServerReference().getId());
log.info("Synchronizing for user {} in server {}.", user.getUserReference().getId(), user.getServerReference().getId());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(user.getServerReference());
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
return updateUserRole(userExperience, roles, userExperience.getLevelOrDefault());
}
@@ -506,27 +549,30 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
page--;
int pageSize = 10;
log.trace("Loading leaderboard page {} for server {}.", page, server.getId());
List<AUserExperience> experiences = userExperienceManagementService.findLeaderBoardUsersPaginated(server, page * pageSize, (page + 1) * pageSize);
log.debug("Loading leaderboard page {} for server {}.", page, server.getId());
List<AUserExperience> experiences = userExperienceManagementService.findLeaderBoardUsersPaginated(server, page, pageSize);
List<LeaderBoardEntry> entries = new ArrayList<>();
log.trace("Found {} experiences.", experiences.size());
log.debug("Found {} experiences.", experiences.size());
int pageOffset = page * pageSize;
for (int i = 0; i < experiences.size(); i++) {
AUserExperience userExperience = experiences.get(i);
entries.add(LeaderBoardEntry.builder().experience(userExperience).rank((page * pageSize) + i + 1).build());
entries.add(LeaderBoardEntry.builder().experience(userExperience).rank(pageOffset + i + 1).build());
}
return LeaderBoard.builder().entries(entries).build();
}
@Override
public LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer) {
log.trace("Retrieving rank for {}", userInAServer.getUserReference().getId());
AUserExperience aUserExperience = userExperienceManagementService.findUserInServer(userInAServer);
log.debug("Retrieving rank for {}", userInAServer.getUserReference().getId());
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServer.getUserInServerId());
if(!aUserExperienceOptional.isPresent()) {
throw new NoExperienceTrackedException();
}
Integer rank = 0;
if(aUserExperience != null) {
LeaderBoardEntryResult rankOfUserInServer = userExperienceManagementService.getRankOfUserInServer(aUserExperience);
if(rankOfUserInServer != null) {
rank = rankOfUserInServer.getRank();
}
AUserExperience aUserExperience = aUserExperienceOptional.get();
LeaderBoardEntryResult rankOfUserInServer = userExperienceManagementService.getRankOfUserInServer(aUserExperience);
if(rankOfUserInServer != null) {
rank = rankOfUserInServer.getRank();
}
return LeaderBoardEntry.builder().experience(aUserExperience).rank(rank).build();
}

View File

@@ -57,7 +57,8 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
@Override
public Long calculateExperienceToNextLevel(Integer level, Long currentExperience) {
AExperienceLevel nextLevel = experienceLevelManagementService.getLevel(level + 1).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
AExperienceLevel nextLevel = experienceLevelManagementService.getLevelOptional(level + 1)
.orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
return nextLevel.getExperienceNeeded() - currentExperience;
}

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.experience.service;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
@@ -10,6 +11,7 @@ import dev.sheldan.abstracto.experience.model.RoleCalculationResult;
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
import dev.sheldan.abstracto.experience.model.template.LevelRole;
import dev.sheldan.abstracto.experience.service.management.ExperienceLevelManagementService;
import dev.sheldan.abstracto.experience.service.management.ExperienceRoleManagementService;
import lombok.extern.slf4j.Slf4j;
@@ -18,9 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -46,6 +46,9 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private RoleService roleService;
/**
* UnSets the current configuration for the passed level, and sets the {@link ARole} to be used for this level
* in the given {@link AServer}
@@ -55,14 +58,43 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Override
public CompletableFuture<Void> setRoleToLevel(Role role, Integer level, Long channelId) {
Long roleId = role.getIdLong();
ARole aRole = roleManagementService.findRole(roleId);
return unsetRole(aRole, channelId).thenAccept(aVoid ->
ARole aRoleToSet = roleManagementService.findRole(roleId);
List<AExperienceRole> experienceRoles = getExperienceRolesAtLevel(level, aRoleToSet.getServer());
List<ARole> rolesToUnset = experienceRoles.stream().map(AExperienceRole::getRole).collect(Collectors.toList());
if(rolesToUnset.size() == 1 && rolesToUnset.contains(aRoleToSet)) {
return CompletableFuture.completedFuture(null);
}
if(!rolesToUnset.contains(aRoleToSet)) {
rolesToUnset.add(aRoleToSet);
}
AExperienceLevel experienceLevel;
if(!experienceRoles.isEmpty()) {
experienceLevel = experienceRoles.get(0).getLevel();
} else {
experienceLevel = experienceLevelService.getLevel(level);
}
AExperienceRole newExperienceRole = experienceRoleManagementService.setLevelToRole(experienceLevel, aRoleToSet);
Long newlyCreatedExperienceRoleId = newExperienceRole.getId();
CompletableFuture<Void> future = new CompletableFuture<>();
unsetRoles(rolesToUnset, channelId, newExperienceRole).thenAccept(aVoid ->
self.unsetRoleInDb(level, roleId)
);
).thenAccept(unused -> future.complete(null)).exceptionally(throwable -> {
self.deleteExperienceRoleViaId(newlyCreatedExperienceRoleId);
future.completeExceptionally(throwable);
return null;
});
return future;
}
@Transactional
public void deleteExperienceRoleViaId(Long newlyCreatedExperienceRoleId) {
AExperienceRole reLoadedRole = experienceRoleManagementService.getExperienceRoleById(newlyCreatedExperienceRoleId);
experienceRoleManagementService.unsetRole(reLoadedRole);
}
/**
* Removes all previous defined {@link AExperienceRole experienceRoles} from the given leve and sets the {@link ARole}
* Removes all previous defined {@link AExperienceRole experienceRoles} from the given level and sets the {@link ARole}
* (defined by its ID) to the level.
* @param level The level which the {@link ARole role} should be set to
* @param roleId The ID of the {@link Role} which should have its level set
@@ -70,9 +102,9 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Transactional
public void unsetRoleInDb(Integer level, Long roleId) {
log.info("Unsetting role {} from level {}.", roleId, level);
AExperienceLevel experienceLevel = experienceLevelService.getLevel(level).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find level %s", level)));
AExperienceLevel experienceLevel = experienceLevelService.getLevelOptional(level).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find level %s", level)));
ARole loadedRole = roleManagementService.findRole(roleId);
experienceRoleManagementService.removeAllRoleAssignmentsForLevelInServer(experienceLevel, loadedRole.getServer());
experienceRoleManagementService.removeAllRoleAssignmentsForLevelInServerExceptRole(experienceLevel, loadedRole.getServer(), loadedRole);
experienceRoleManagementService.setLevelToRole(experienceLevel, loadedRole);
}
@@ -83,30 +115,54 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
* configuration
*/
@Override
public CompletableFuture<Void> unsetRole(ARole role, Long feedbackChannelId) {
AChannel channel = channelManagementService.loadChannel(feedbackChannelId);
Optional<AExperienceRole> roleInServerOptional = experienceRoleManagementService.getRoleInServerOptional(role);
if(roleInServerOptional.isPresent()) {
AExperienceRole roleInServer = roleInServerOptional.get();
if(!roleInServer.getUsers().isEmpty()) {
log.info("Recalculating the roles for {} users, because their current role was removed from experience tracking.", roleInServer.getUsers().size());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(role.getServer());
roles.removeIf(role1 -> role1.getId().equals(roleInServer.getId()));
Long roleId = role.getId();
CompletableFutureList<RoleCalculationResult> calculationResults = userExperienceService.executeActionOnUserExperiencesWithFeedBack(roleInServer.getUsers(), channel,
(AUserExperience ex) -> userExperienceService.updateUserRole(ex, roles, ex.getLevelOrDefault()));
return calculationResults.getMainFuture().thenAccept(aVoid ->
self.persistData(calculationResults, roleId)
);
} else {
log.info("Roles does not have any active users, no need to remove them.");
experienceRoleManagementService.unsetRole(roleInServer);
return CompletableFuture.completedFuture(null);
}
} else {
log.info("Experience role is not define in server - skipping unset.");
public CompletableFuture<Void> unsetRoles(ARole role, Long feedbackChannelId) {
return unsetRoles(Arrays.asList(role), feedbackChannelId);
}
@Override
public List<AExperienceRole> getExperienceRolesAtLevel(Integer level, AServer server) {
AExperienceLevel levelObj = experienceLevelService.getLevel(level);
return experienceRoleManagementService.getExperienceRolesAtLevelInServer(levelObj, server);
}
@Override
public CompletableFuture<Void> unsetRoles(List<ARole> rolesToUnset, Long feedbackChannelId) {
return unsetRoles(rolesToUnset, feedbackChannelId, null);
}
@Override
public CompletableFuture<Void> unsetRoles(List<ARole> rolesToUnset, Long feedbackChannelId, AExperienceRole toAdd) {
if(rolesToUnset.isEmpty()) {
return CompletableFuture.completedFuture(null);
}
AServer server = rolesToUnset.get(0).getServer();
AChannel channel = channelManagementService.loadChannel(feedbackChannelId);
List<AExperienceRole> experienceRolesNecessaryToRemove = new ArrayList<>();
List<AUserExperience> usersToUpdate = new ArrayList<>();
rolesToUnset.forEach(role -> {
Optional<AExperienceRole> roleInServerOptional = experienceRoleManagementService.getRoleInServerOptional(role);
if(roleInServerOptional.isPresent()) {
AExperienceRole experienceRole = roleInServerOptional.get();
experienceRolesNecessaryToRemove.add(experienceRole);
usersToUpdate.addAll(experienceRole.getUsers());
} else {
log.info("Experience role {} is not defined in server {} - skipping unset.", role.getId(), server.getId());
}
});
log.info("Recalculating the roles for {} users, because their current role was removed from experience tracking.", usersToUpdate.size());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
roles.removeIf(role1 -> experienceRolesNecessaryToRemove.stream().anyMatch(aExperienceRole -> aExperienceRole.getId().equals(role1.getId())));
if(toAdd != null) {
roles.add(toAdd);
}
roles.sort(Comparator.comparing(innerRole -> innerRole.getLevel().getLevel()));
List<Long> roleIds = experienceRolesNecessaryToRemove.stream().map(AExperienceRole::getId).collect(Collectors.toList());
if(toAdd != null) {
roleIds.removeIf(aLong -> aLong.equals(toAdd.getRole().getId()));
}
CompletableFutureList<RoleCalculationResult> calculationResults = userExperienceService.executeActionOnUserExperiencesWithFeedBack(usersToUpdate, channel,
(AUserExperience ex) -> userExperienceService.updateUserRole(ex, roles, ex.getLevelOrDefault()));
return calculationResults.getMainFuture().thenAccept(aVoid -> self.persistData(calculationResults, roleIds));
}
/**
@@ -115,13 +171,15 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
* have to remove the existing {@link AExperienceRole experienceRole}
* @param results A list of {@link CompletableFuture futures} which each contain a {@link RoleCalculationResult result}, for the members who got
* their {@link AExperienceRole experienceRole} removed
* @param roleId The ID of the {@link AExperienceRole experienceRole} which was removed from the experience roles
* @param roleIds The IDs of the {@link AExperienceRole experienceRoles} which were removed from the experience roles
*/
@Transactional
public void persistData(CompletableFutureList<RoleCalculationResult> results, Long roleId) {
log.info("Persisting {} role calculation results after changing the role {}.", results.getFutures().size(), roleId);
AExperienceRole roleInServer = experienceRoleManagementService.getExperienceRoleById(roleId);
experienceRoleManagementService.unsetRole(roleInServer);
public void persistData(CompletableFutureList<RoleCalculationResult> results, List<Long> roleIds) {
log.info("Persisting {} role calculation results.", results.getFutures().size());
roleIds.forEach(roleId -> {
log.info("Deleting experience role {}.", roleId);
deleteExperienceRoleViaId(roleId);
});
userExperienceService.syncRolesInStorage(results.getObjects());
}
@@ -130,7 +188,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
if(roles == null || roles.isEmpty()) {
return null;
}
log.trace("Calculating role for level {} in server {}. Using {} roles in our config.", currentLevel, roles.get(0).getServer().getId(), roles.size());
log.debug("Calculating role for level {} in server {}. Using {} roles in our config.", currentLevel, roles.get(0).getServer().getId(), roles.size());
AExperienceRole lastRole = null;
for (AExperienceRole experienceRole : roles) {
if(currentLevel >= experienceRole.getLevel().getLevel()) {
@@ -144,7 +202,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Override
public AExperienceLevel getLevelOfNextRole(AExperienceLevel startLevel, AServer server) {
log.trace("Calculating level of next role for level {} in server {}.", startLevel.getLevel(), server.getId());
log.debug("Calculating level of next role for level {} in server {}.", startLevel.getLevel(), server.getId());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
roles = roles.stream().filter(role -> role.getLevel().getLevel() > startLevel.getLevel()).collect(Collectors.toList());
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
@@ -152,4 +210,21 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
return aExperienceRole != null ? aExperienceRole.getLevel() : AExperienceLevel.builder().level(200).build();
}
@Override
public List<LevelRole> loadLevelRoleConfigForServer(AServer server) {
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
List<LevelRole> levelRoles = new ArrayList<>();
roles.forEach(aExperienceRole -> {
Role role = roleService.getRoleFromGuild(aExperienceRole.getRole());
LevelRole levelRole = LevelRole
.builder()
.role(role)
.roleId(aExperienceRole.getId())
.level(aExperienceRole.getLevel().getLevel())
.build();
levelRoles.add(levelRole);
});
return levelRoles;
}
}

View File

@@ -1,15 +1,19 @@
package dev.sheldan.abstracto.experience.service.management;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.repository.ExperienceLevelRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class ExperienceLevelManagementServiceBean implements ExperienceLevelManagementService {
public class ExperienceLevelManagementServiceBean implements ExperienceLevelManagementService {
@Autowired
private ExperienceLevelRepository experienceLevelRepository;
@@ -30,12 +34,22 @@ public class ExperienceLevelManagementServiceBean implements ExperienceLevelM
}
@Override
public Optional<AExperienceLevel> getLevel(Integer level) {
public Optional<AExperienceLevel> getLevelOptional(Integer level) {
return experienceLevelRepository.findById(level);
}
@Override
public AExperienceLevel getLevel(Integer level) {
return getLevelOptional(level).orElseThrow(() -> new AbstractoRunTimeException("Level not found."));
}
@Override
public List<AExperienceLevel> getLevelConfig() {
return experienceLevelRepository.findAll();
}
@Override
public Map<Integer, AExperienceLevel> getLevelConfigAsMap() {
return getLevelConfig().stream().collect(Collectors.toMap(AExperienceLevel::getLevel, Function.identity()));
}
}

View File

@@ -30,10 +30,14 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
* @param server The server in which this should happen
*/
@Override
public void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server) {
public void removeAllRoleAssignmentsForLevelInServerExceptRole(AExperienceLevel level, AServer server, ARole role) {
List<AExperienceRole> existingExperienceRoles = experienceRoleRepository.findByLevelAndRoleServer(level, server);
log.info("Removing all role assignments ({}) for level {} in server {}.", existingExperienceRoles.size(), level.getLevel(), server.getId());
existingExperienceRoles.forEach(existingRole -> experienceRoleRepository.delete(existingRole));
existingExperienceRoles.forEach(existingRole -> {
if(!existingRole.getRole().getId().equals(role.getId())) {
experienceRoleRepository.delete(existingRole);
}
});
}
@Override
@@ -81,7 +85,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
AExperienceRole experienceRole;
log.info("Setting role {} in server {} to level {}.", role.getId(), role.getServer().getId(), level.getLevel());
if(byRoleServerAndRoleOptional.isPresent()) {
log.trace("Role already existed. Updating.");
log.debug("Role already existed. Updating.");
experienceRole = byRoleServerAndRoleOptional.get();
experienceRole.setLevel(level);
} else {
@@ -92,9 +96,14 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
.server(role.getServer())
.role(role)
.build();
log.trace("Role did not exist. Creating new.");
log.debug("Role did not exist. Creating new.");
return experienceRoleRepository.save(experienceRole);
}
return experienceRole;
}
@Override
public List<AExperienceRole> getExperienceRolesAtLevelInServer(AExperienceLevel level, AServer server) {
return experienceRoleRepository.findByLevelAndRoleServer(level, server);
}
}

View File

@@ -45,7 +45,7 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
@Override
public AUserExperience createUserInServer(AUserInAServer aUserInAServer) {
log.info("Creating user experience for user {} in server {}.", aUserInAServer.getUserReference().getId(),aUserInAServer.getServerReference().getId());
AExperienceLevel startingLevel = experienceLevelManagementService.getLevel(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0)));
AExperienceLevel startingLevel = experienceLevelManagementService.getLevelOptional(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0)));
return AUserExperience
.builder()
.experience(0L)
@@ -64,8 +64,8 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
}
@Override
public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer start, Integer end) {
return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(start, end));
public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer page, Integer size) {
return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(page, size));
}
@Override

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="experience-tables/tables.xml" relativeToChangelogFile="true"/>
<include file="experience-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_gain_channel_group_type-insertion">
<insert tableName="channel_group_type">
<column name="group_type_key" value="experienceGain"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="experienceModule" value="(SELECT id FROM module WHERE name = 'experience')"/>
<property name="experienceFeature" value="(SELECT id FROM feature WHERE key = 'experience')"/>
<changeSet author="Sheldan" id="experience-commands">
@@ -64,6 +64,11 @@
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="levelRoles"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -3,12 +3,13 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="experience_level.xml" relativeToChangelogFile="true"/>
<include file="feature.xml" relativeToChangelogFile="true"/>
<include file="module.xml" relativeToChangelogFile="true"/>
<include file="command.xml" relativeToChangelogFile="true"/>
<include file="experience_job.xml" relativeToChangelogFile="true"/>
<include file="channel_group_types.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience-job-insert">
<insert tableName="scheduler_job">
<column name="name" value="experienceJob"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_levels-insert">
<insert tableName="experience_level">
<column name="level" value="0"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_feature-insertion">
<insert tableName="feature">
<column name="key" value="experience"/>

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience-module-insertion">
<insert tableName="module">
<column name="name" value="experience"/>

View File

@@ -3,16 +3,16 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="disabled_experience_role-table">
<createTable tableName="disabled_experience_role">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="disabled_experience_role_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>

View File

@@ -3,20 +3,20 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_level-table">
<createTable tableName="experience_level">
<column name="level" type="INTEGER">
<constraints nullable="false" primaryKey="true" primaryKeyName="experience_level_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="experience_needed" type="BIGINT">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
</createTable>
<sql>

View File

@@ -3,16 +3,16 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_role-table">
<createTable tableName="experience_role">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="experience_role_pkey"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="level_id" type="INTEGER">

View File

@@ -3,9 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="experience_level.xml" relativeToChangelogFile="true"/>
<include file="experience_role.xml" relativeToChangelogFile="true"/>
<include file="user_experience.xml" relativeToChangelogFile="true"/>

View File

@@ -3,25 +3,25 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="user_experience-table">
<createTable tableName="user_experience">
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="user_experience_pkey"/>
</column>
<column name="experience" type="BIGINT">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="experience_gain_disabled" type="BOOLEAN">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="message_count" type="BIGINT">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="role_id" type="BIGINT"/>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="experience_level.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,212 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="experience_levels_expansion-insert">
<insert tableName="experience_level">
<column name="level" value="101"/>
<column name="experience_needed" value="1954350"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="102"/>
<column name="experience_needed" value="2010505"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="103"/>
<column name="experience_needed" value="2067725"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="104"/>
<column name="experience_needed" value="2126020"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="105"/>
<column name="experience_needed" value="2185400"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="106"/>
<column name="experience_needed" value="2245875"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="107"/>
<column name="experience_needed" value="2307455"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="108"/>
<column name="experience_needed" value="2370150"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="109"/>
<column name="experience_needed" value="2433970"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="110"/>
<column name="experience_needed" value="2498925"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="111"/>
<column name="experience_needed" value="2565025"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="112"/>
<column name="experience_needed" value="2632280"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="113"/>
<column name="experience_needed" value="2700700"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="114"/>
<column name="experience_needed" value="2770295"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="115"/>
<column name="experience_needed" value="2841075"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="116"/>
<column name="experience_needed" value="2913050"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="117"/>
<column name="experience_needed" value="2986230"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="118"/>
<column name="experience_needed" value="3060625"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="119"/>
<column name="experience_needed" value="3136245"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="120"/>
<column name="experience_needed" value="3213100"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="121"/>
<column name="experience_needed" value="3291200"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="122"/>
<column name="experience_needed" value="3370555"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="123"/>
<column name="experience_needed" value="3451175"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="124"/>
<column name="experience_needed" value="3533070"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="125"/>
<column name="experience_needed" value="3616250"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="126"/>
<column name="experience_needed" value="3700725"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="127"/>
<column name="experience_needed" value="3786505"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="128"/>
<column name="experience_needed" value="3873600"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="129"/>
<column name="experience_needed" value="3962020"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="130"/>
<column name="experience_needed" value="4051775"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="131"/>
<column name="experience_needed" value="4142875"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="132"/>
<column name="experience_needed" value="4235330"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="133"/>
<column name="experience_needed" value="4329150"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="134"/>
<column name="experience_needed" value="4424345"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="135"/>
<column name="experience_needed" value="4520925"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="136"/>
<column name="experience_needed" value="4618900"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="137"/>
<column name="experience_needed" value="4718280"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="138"/>
<column name="experience_needed" value="4819075"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="139"/>
<column name="experience_needed" value="4921295"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="140"/>
<column name="experience_needed" value="5024950"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="141"/>
<column name="experience_needed" value="5130050"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="142"/>
<column name="experience_needed" value="5236605"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="143"/>
<column name="experience_needed" value="5344625"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="144"/>
<column name="experience_needed" value="5454120"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="145"/>
<column name="experience_needed" value="5565100"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="146"/>
<column name="experience_needed" value="5677575"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="147"/>
<column name="experience_needed" value="5791555"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="148"/>
<column name="experience_needed" value="5907050"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="149"/>
<column name="experience_needed" value="6024070"/>
</insert>
<insert tableName="experience_level">
<column name="level" value="150"/>
<column name="experience_needed" value="6142625"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -257,6 +257,7 @@
<xsd:attributeGroup name="changeLogAttributes">
<xsd:attribute name="logicalFilePath" type="xsd:string"/>
<xsd:attribute name="context" type="xsd:string"/>
<xsd:attribute name="changeLogId" type="xsd:string"/>
<xsd:attribute name="objectQuotingStrategy" type="objectQuotingStrategy" default="LEGACY"/>
</xsd:attributeGroup>
@@ -277,11 +278,12 @@
<xsd:attribute name="created" type="xsd:string"/>
<xsd:attribute name="runOrder" type="xsd:string"/>
<xsd:attribute name="ignore" type="booleanExp"/>
<xsd:attribute name="runWith" type="xsd:string" />
</xsd:attributeGroup>
<!-- Attributes for changes -->
<xsd:attributeGroup name="changeAttributes">
<xsd:anyAttribute namespace="##any" processContents="lax"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:attributeGroup>
<!-- Attributes for constraints -->
@@ -306,7 +308,7 @@
<xsd:attribute name="validateNullable" type="booleanExp"/>
<xsd:attribute name="validateUnique" type="booleanExp"/>
<xsd:attribute name="validatePrimaryKey" type="booleanExp"/>
<xsd:attribute name="validateForeignKey " type="booleanExp"/>
<xsd:attribute name="validateForeignKey" type="booleanExp"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="column">
@@ -420,9 +422,10 @@
<xsd:attribute name="incrementBy" type="xsd:string"/>
<xsd:attribute name="maxValue" type="xsd:string"/>
<xsd:attribute name="minValue" type="xsd:string"/>
<xsd:attribute name="ordered" type="booleanExp"/>
<xsd:attribute name="ordered" type="xsd:string"/>
<xsd:attribute name="cacheSize" type="xsd:string"/>
<xsd:attribute name="cycle" type="booleanExp">
<xsd:attribute name="dataType" type="xsd:string" />
<xsd:attribute name="cycle" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
true for a cycling sequence, false for a non-cycling sequence.
@@ -481,11 +484,15 @@
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="constraintName" type="xsd:string"/>
<xsd:attribute name="dropIndex" type="booleanExp"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="addUniqueConstraint">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="columnNames" type="xsd:string"
@@ -616,6 +623,7 @@
<xsd:attribute name="header" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="allowUpdate" type="booleanExp"/>
<xsd:attribute name="defaultValue" type="xsd:string"/>
<xsd:attribute name="defaultValueNumeric" type="xsd:string"/>
<xsd:attribute name="defaultValueDate" type="xsd:string"/>
@@ -919,6 +927,7 @@
<xsd:attribute name="schemaName" type="xsd:string"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="columnName" type="xsd:string" use="required"/>
<xsd:attribute name="columnDataType" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -957,6 +966,7 @@
<xsd:attributeGroup ref="tableNameAttribute"/>
<xsd:attribute name="tablespace" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1124,7 +1134,7 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="tag" type="xsd:string" use="required"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
@@ -1226,7 +1236,6 @@
<xsd:complexType>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attributeGroup ref="sequenceAttributes"/>
<xsd:attribute name="dataType" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -1283,7 +1292,7 @@
</xsd:sequence>
<xsd:attributeGroup ref="changeAttributes"/>
<xsd:attribute name="class" type="xsd:string" use="required"/>
<xsd:anyAttribute processContents="lax" />
</xsd:complexType>
</xsd:element>
@@ -1374,4 +1383,4 @@
</xsd:sequence>
</xsd:group>
</xsd:schema>
</xsd:schema>

View File

@@ -3,8 +3,9 @@
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog-3.8.xsd" >
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.0-experience/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.15/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -74,11 +74,11 @@ public class LeaderBoardCommandTest {
AUserInAServer userInAServer = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(userInAServer);
when(userExperienceService.findLeaderBoardData(server, expectedPage)).thenReturn(leaderBoard);
when(converter.fromLeaderBoard(leaderBoard)).thenReturn(new ArrayList<>());
when(converter.fromLeaderBoard(leaderBoard)).thenReturn(CompletableFuture.completedFuture(null));
LeaderBoardEntry executingUserRank = Mockito.mock(LeaderBoardEntry.class);
when(userExperienceService.getRankOfUserInServer(userInAServer)).thenReturn(executingUserRank);
LeaderBoardEntryModel leaderBoardEntryModel = Mockito.mock(LeaderBoardEntryModel.class);
when(converter.fromLeaderBoardEntry(executingUserRank)).thenReturn(CompletableFuture.completedFuture(leaderBoardEntryModel));
when(converter.fromLeaderBoardEntry(Arrays.asList(executingUserRank))).thenReturn(CompletableFuture.completedFuture(Arrays.asList(leaderBoardEntryModel)));
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(LeaderBoardCommand.LEADER_BOARD_POST_EMBED_TEMPLATE), any(LeaderBoardModel.class), eq(SERVER_ID))).thenReturn(messageToSend);
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);

View File

@@ -73,7 +73,7 @@ public class RankTest {
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(aUserInAServer);
when(userExperienceService.getRankOfUserInServer(aUserInAServer)).thenReturn(leaderBoardEntry);
LeaderBoardEntryModel leaderBoardEntryModel = Mockito.mock(LeaderBoardEntryModel.class);
when(converter.fromLeaderBoardEntry(leaderBoardEntry)).thenReturn(CompletableFuture.completedFuture(leaderBoardEntryModel));
when(converter.fromLeaderBoardEntry(Arrays.asList(leaderBoardEntry))).thenReturn(CompletableFuture.completedFuture(Arrays.asList(leaderBoardEntryModel)));
when(self.renderAndSendRank(eq(context), any(RankModel.class), eq(leaderBoardEntryModel))).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);

Some files were not shown because too many files have changed in this diff Show More