mirror of
https://github.com/Sheldan/OnePlusBot.git
synced 2026-01-08 02:17:48 +00:00
Compare commits
107 Commits
oneplusbot
...
oneplusbot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36ac023eea | ||
|
|
be13313000 | ||
|
|
b6180614ff | ||
|
|
e4434fcb25 | ||
|
|
b3bbd20da0 | ||
|
|
fe50e1331b | ||
|
|
e77c448824 | ||
|
|
8cc2ed5e96 | ||
|
|
aaf4afe92e | ||
|
|
17e24b14f4 | ||
|
|
ae88377d30 | ||
|
|
4e645885f3 | ||
|
|
77bb7b043b | ||
|
|
9f8d4ebcc8 | ||
|
|
021d07bf47 | ||
|
|
0a7eda239f | ||
|
|
a8587d29af | ||
|
|
e38f5c8382 | ||
|
|
3ab491b5f3 | ||
|
|
ed85b1955f | ||
|
|
f83042c84f | ||
|
|
b11b49e5c4 | ||
|
|
9d1382019f | ||
|
|
6e25ac91cb | ||
|
|
44e3f8656c | ||
|
|
c8a6f67af5 | ||
|
|
a39942beef | ||
|
|
ca36645197 | ||
|
|
e177b5f559 | ||
|
|
9f11ec5ffa | ||
|
|
5378a4038b | ||
|
|
d448dfbf9b | ||
|
|
f0b548a97e | ||
|
|
b0c2c24dce | ||
|
|
658683c013 | ||
|
|
8c8cadefdd | ||
|
|
8e9a7004a2 | ||
|
|
29fb53fb7a | ||
|
|
6d23fffc77 | ||
|
|
d816a8a48c | ||
|
|
386011d2e9 | ||
|
|
015609f9d2 | ||
|
|
35a6f0aeeb | ||
|
|
743195b137 | ||
|
|
9f35781f2d | ||
|
|
dbf131abfe | ||
|
|
05dbb1fc2f | ||
|
|
47284686d6 | ||
|
|
46ef5435c7 | ||
|
|
bcfaf1c928 | ||
|
|
124d45ba5b | ||
|
|
4cdaf87412 | ||
|
|
13cf06e1dc | ||
|
|
e8ae0f430d | ||
|
|
cda9d1a2b8 | ||
|
|
653246f3ee | ||
|
|
0879c7cc93 | ||
|
|
4ea878dd42 | ||
|
|
562f5ae9e1 | ||
|
|
92925d176f | ||
|
|
6a5f45c416 | ||
|
|
c7e8fd315f | ||
|
|
95ad8fdd3a | ||
|
|
51775b454e | ||
|
|
aa4de8f571 | ||
|
|
eae07fd07c | ||
|
|
c492640cd7 | ||
|
|
2c49cf2918 | ||
|
|
60ac314ecc | ||
|
|
c82ef9ac18 | ||
|
|
6369ae7c01 | ||
|
|
f9b2174f84 | ||
|
|
d5c8509ab0 | ||
|
|
eaddea63b3 | ||
|
|
7dc141a8a4 | ||
|
|
6652c90edb | ||
|
|
d7f5fc21d6 | ||
|
|
bf98d5db3a | ||
|
|
57fb34920d | ||
|
|
3f959f3bbb | ||
|
|
0380720ec8 | ||
|
|
5bea74cb22 | ||
|
|
1b970ba0a8 | ||
|
|
a707b10cfd | ||
|
|
124d29769e | ||
|
|
d1aa2d5276 | ||
|
|
4d569d4ec0 | ||
|
|
81e58c3f7b | ||
|
|
c04041cb35 | ||
|
|
37e566a957 | ||
|
|
f7ca31a0c8 | ||
|
|
8da31831b0 | ||
|
|
ed5b821da3 | ||
|
|
cd875535d4 | ||
|
|
8a38dd3d1a | ||
|
|
86eac5f2a5 | ||
|
|
8644af678f | ||
|
|
6055a5e15f | ||
|
|
aa71ad3f97 | ||
|
|
2985e46979 | ||
|
|
93dfef5572 | ||
|
|
cab8cf1a8f | ||
|
|
2066a2254d | ||
|
|
75a5a1ff1a | ||
|
|
97eb1761e3 | ||
|
|
cc3d4f38ab | ||
|
|
c42b540bb6 |
4
.env
Normal file
4
.env
Normal file
@@ -0,0 +1,4 @@
|
||||
REGISTRY_PREFIX=harbor.sheldan.dev/oneplus-bot/
|
||||
ABSTRACTO_PREFIX=harbor.sheldan.dev/abstracto/
|
||||
VERSION=1.6.14
|
||||
ABSTRACTO_VERSION=1.5.19
|
||||
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Bug Report
|
||||
description: Found a bug that needs fixing?
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: General Troubleshooting
|
||||
description: You confirm to have made the following checks first.
|
||||
options:
|
||||
- label: I have checked for similar issues on the Issue-tracker.
|
||||
required: true
|
||||
- label: I have updated to the latest version
|
||||
required: true
|
||||
- label: I have checked the branches or the maintainers' PRs for upcoming bug fixes.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "General information about the bug"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Steps to reproduce"
|
||||
description: "What happened when the bug occurred?"
|
||||
placeholder: "1. ..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Expected behaviour"
|
||||
description: "What should happen?"
|
||||
placeholder: "It should..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Actual behaviour"
|
||||
description: "What did happen instead?"
|
||||
placeholder: "It actually ..."
|
||||
validations:
|
||||
required: true
|
||||
36
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Feature request
|
||||
description: Want some functionality added?
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: General Information
|
||||
description: You confirm to have made the following checks first.
|
||||
options:
|
||||
- label: I have checked for similar issues on the Issue-tracker.
|
||||
required: true
|
||||
- label: I have updated to the latest version
|
||||
required: true
|
||||
- label: I have checked the branches or the maintainers' PRs for upcoming features fixes.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "General description of the feature"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Feature worth and general use"
|
||||
description: "Why should this exist?"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Suggestions for implementation"
|
||||
description: "Any ideas about what the feature should behave/look like? Commands?"
|
||||
placeholder: "It should..."
|
||||
validations:
|
||||
required: false
|
||||
|
||||
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@@ -17,11 +17,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
persist-credentials: false
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Build with Maven
|
||||
run: mvn -s settings.xml -B install --file pom.xml
|
||||
env:
|
||||
|
||||
37
.github/workflows/release.yml
vendored
37
.github/workflows/release.yml
vendored
@@ -6,13 +6,14 @@ jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Java for publishing to GitHub Packages
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Load current version
|
||||
id: version
|
||||
run: echo "version=$(mvn -s settings.xml --file pom.xml -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive exec:exec)" >> $GITHUB_ENV
|
||||
@@ -22,17 +23,25 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
user: Sheldan
|
||||
token: ${{ secrets.ABSTRACTO_PAT }}
|
||||
- name: Login to GitHub Packages Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: docker.pkg.github.com
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Push deployment container
|
||||
working-directory: ./deployment/image-packaging/src/main/docker
|
||||
registry: harbor.sheldan.dev
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_TOKEN }}
|
||||
- name: Load env files
|
||||
id: dotenv
|
||||
uses: falti/dotenv-action@v1.0.4
|
||||
with:
|
||||
path: .env
|
||||
- name: Push container
|
||||
run: docker-compose build && docker-compose push
|
||||
env:
|
||||
REGISTRY_PREFIX: docker.pkg.github.com/sheldan/oneplusbot/
|
||||
VERSION: ${{ env.version }}
|
||||
ABSTRACTO_VERSION: 1.2.17
|
||||
ABSTRACTO_REGISTRY_PREFIX: docker.pkg.github.com/sheldan/abstracto/
|
||||
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
|
||||
VERSION: ${{ steps.dotenv.outputs.version }}
|
||||
- name: Helm push
|
||||
working-directory: ./deployment/helm/
|
||||
run: |-
|
||||
helm registry login -u '${{ secrets.HARBOR_USERNAME }}' -p '${{ secrets.HARBOR_TOKEN }}' harbor.sheldan.dev
|
||||
helm package oneplus-bot
|
||||
helm push oneplus-bot*.tgz oci://harbor.sheldan.dev/oneplus-bot
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Sheldan
|
||||
Copyright (c) 2022 Sheldan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
148
PRIVACY_POLICY.md
Normal file
148
PRIVACY_POLICY.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# r/oneplus Discord bot privacy policy
|
||||
|
||||
Last updated: 06.09.2021
|
||||
|
||||
## Description
|
||||
|
||||
The bot requires some information to function properly and in a reasonable way.
|
||||
The detailed list of what information is stored and processed is the following:
|
||||
|
||||
### General
|
||||
* your Discord user ID (in combination with the server ID) is used to uniquely identify you and associate various properties, such as experience, level, opened modmail threads etc
|
||||
* the IDs of the servers this bot is in
|
||||
* the IDs of the channel in the servers this bot is in
|
||||
* the names of channel groups which were given by their creator
|
||||
* the server aliases which were created for commands
|
||||
* the name of emotes which are used in the bot for convenience, if they are customized
|
||||
* towards which channel (identified by ID) certain messages by the bot are posted. e.g. logging, news, starboard
|
||||
* **no message content, username, channel name or role name is stored, except at the places where its mentioned**
|
||||
* a logfile is used in order to examine any malfunctions, the content is deleted after 7 days
|
||||
* most of the stored records have a 'created' and 'updated' timestamp, in order to assist in examining bugs and malfunctions
|
||||
* which commands have which cooldown in which channel group and in which channel group they are disabled
|
||||
* which channel is in which channel group
|
||||
* which role is allowed to execute which command
|
||||
* which features are enabled
|
||||
* which feature modes are enabled
|
||||
|
||||
### Moderation
|
||||
* the date of the latest report via the reaction report system, in order to disallow quick reports
|
||||
* mute reason, duration, mute date, who muted whom and in which message was the mute executed
|
||||
* the names of filtered invite link servers in order to find out if it would be valid to allow the invite
|
||||
* any configured allowed invite links the server ID and the actually used invite
|
||||
* this is necessary in order to determine the server via its ID and allow other unknown invite links. The invite link is necessary as there is no way to map server ID to actual server
|
||||
* configured profanity regexes
|
||||
* reported profanities, including which message contains the profanity, and the message which was used to report the profanity, and whether it was identified as a true profanity
|
||||
* messages and users which were reported via reaction reports and how many times they were reported, but not *who* reported a message
|
||||
* **the text of notes regarding users**
|
||||
* this is used to enable taking notes about users, and the content is stored directly
|
||||
* meta information regarding warnings
|
||||
* **reason for the warning**
|
||||
* date of the warning
|
||||
* the user who warned a user
|
||||
* whether the warning was decayed and when
|
||||
|
||||
### Embedded messages
|
||||
* embedded message information
|
||||
* this information includes who embedded which message in which channel and is deleted after a few days
|
||||
|
||||
### Emote usage tracking
|
||||
* the name of emotes which are being tracked in the emote usage tracking system for purely convenience reasons
|
||||
* **who** used which emote is **not** tracked
|
||||
* at which day an emote was used how many times
|
||||
|
||||
### News
|
||||
* general information about news posts
|
||||
* the source message of the command, the created news post, and the author in order to enable the update mechanism
|
||||
|
||||
### Referral system
|
||||
* the date of the latest referral post in order to enforce the referral bump mechanism
|
||||
|
||||
### Reminder
|
||||
* **the message content** in order to provide you with the reminder text
|
||||
* the date it was created, and the date it is due
|
||||
* the id of the message which contained the command
|
||||
* whether you have been reminded
|
||||
|
||||
### Starboard
|
||||
* the message which was the origin for the starboard post
|
||||
* the message which was the resulting starboard post
|
||||
* the author of the message and the amount of stars
|
||||
* who reacted to a starboard post
|
||||
* this is necessary to provide the information about 'top star giver' and to disallow duplicate starboard reactions
|
||||
|
||||
### Suggestion
|
||||
* *the message content* of the message used to create the suggestion
|
||||
* this was used for the message used to update the status of a suggestion, but this is currently disabled
|
||||
* the author of the suggestion and the message which has been posted in the suggestions channel
|
||||
* every suggestion will be deleted completely from the database a few days after it has reached a final state (rejected, denied, accepted)
|
||||
* whether you voted for a suggestion and which decision you took
|
||||
|
||||
### Leveling system
|
||||
* the amount of messages which were considered for the leveling system
|
||||
* it only considers a message once per minute, so it does not directly translate to your absolute message count
|
||||
* the amount of experience, and the experience level you have
|
||||
* whether experience gain has been disabled for you
|
||||
* the role you received because of the experience system
|
||||
* which roles are configured to be used as experience roles and at which level they are assigned
|
||||
* which roles are used to disable experience gain
|
||||
|
||||
### FAQ
|
||||
* the names of FAQ commands
|
||||
* in which channel groups a FAQ command has a response
|
||||
* the aliases of FAQ commands
|
||||
* information about the actual FAQ message
|
||||
* the **content** of the message
|
||||
* the **URL** of the image used
|
||||
* the color of the embed to be used
|
||||
* the ID of the user to be used as author
|
||||
* the amount of times a FAQ response has been used
|
||||
|
||||
### Assignable roles
|
||||
* the names of assignable role places and assignable role button text, together with the associated emote markdown (if given)
|
||||
* the assigned assignable roles for each member in order to provide the 'unique' assignable role functionality
|
||||
|
||||
## Grafana dashboard
|
||||
|
||||
There is also a [Grafana](https://grafana.com/) dashboard in order to inspect how the bot is operating.
|
||||
The information visible in this dashboard is:
|
||||
|
||||
* message events
|
||||
* Discord gateway ping
|
||||
* starboard reactions
|
||||
* amount of command executions
|
||||
* emotes currently being processed for tracking
|
||||
* embedded messages
|
||||
* invite filter activity
|
||||
* amount of experience which is currently being processed
|
||||
|
||||
All of this information cannot be linked to any user (or any server for that matter, if the bot would be in multiple servers) and is deleted after 15 days.
|
||||
|
||||
|
||||
## How can I decide which information is collected?
|
||||
It is not possible to opt-out of singular sub-services of the bot. Should you decide that your information should not be collected, please cease usage of the bot immediately (leave any guild the bot operates in).
|
||||
|
||||
_Should you decide to no longer utilize the bot, you may request your data to be erased within 30 days as per GDPR if you are a citizen of the EU. You can do this by sending an email to oneplus.appeals@pm.me with the subject: GDPR Data removal <Username#0000> <UserId>. If your request is incomplete, we cannot acknowledge it and therefore your data will not be removed. In order to identify authentic requests, please contact modmail beforehand by sending a direct message to the bot and stating your intention._
|
||||
|
||||
|
||||
## Legal information
|
||||
The bot is not an official application from OnePlus or OPPO. You agree to use the bot at your own risk. The developers of the bot are not responsible for any damage done to your device, your computer or any other property.
|
||||
|
||||
We cannot promise you, as the user, to always update you when this Privacy Policy has changed. You can check the most recent version here. Important changes will be posted in the bot changelog channel of the r/oneplus Discord server.
|
||||
|
||||
OnePlus and OPPO are legal owners of OxygenOS. Visit https://oneplus.com/brand to view information about OnePlus.
|
||||
|
||||
## Open source content
|
||||
This bot uses the following open source libraries and frameworks:
|
||||
|
||||
* [abstracto](https://github.com/Sheldan/abstracto) is used as a base for this bot, providing a lot of the functionalities
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper used
|
||||
* [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.
|
||||
* [Ehcache](https://github.com/ehcache/ehcache3) is used as a caching implementation.
|
||||
* [Lombok](https://github.com/rzwitserloot/lombok) is used as a framework in order to speed up creation of container classes and builders.
|
||||
* [Quartz](https://github.com/quartz-scheduler/quartz) is used as a scheduling framework in order to provide functionalities which either require a delayed or cronjob behaviour.
|
||||
* [Docker](https://github.com/docker) is used to package the application into a container and [Docker Compose](https://github.com/docker/compose) is used to orchestrate the containers
|
||||
* [Liquibase](https://github.com/liquibase/liquibase) is used to manage changes to the database
|
||||
* [Prometheus](https://prometheus.io) to scrap and collect the metrics about how the bot is operating
|
||||
* [Grafana](https://grafana.com) to visualize metrics of the bot
|
||||
14
README.md
14
README.md
@@ -1,11 +1,21 @@
|
||||
# r/oneplus Discord server bot
|
||||
|
||||
This repository contains the rewrite of the [Bot](https://github.com/Rithari/OnePlusBot), which is still in use. The features will be gradually be ported
|
||||
and most of them will be in [abstracto](https://github.com/Sheldan/abstracto), but some of the features need to be customized, as they are r/oneplus specific.
|
||||
This repository contains the rewrite of the [Bot](https://github.com/Rithari/OnePlusBot). It is developed by customizing [abstracto](https://github.com/Sheldan/abstracto), because some features are r/oneplus specific.
|
||||
|
||||
The migration of the existing data from the database is handled via one time migration, and can be found [here](https://github.com/Sheldan/OnePlusBot-migration).
|
||||
|
||||
The FAQ configuration can be found [here](https://github.com/Sheldan/OnePlusBot-faq/).
|
||||
|
||||
Custom features which were ported
|
||||
- [x] FAQ
|
||||
- [x] Setup channel handling
|
||||
- [x] Referral link handling
|
||||
|
||||
# Technologies used in addition to the ones provided in abstracto
|
||||
- [grafana](https://github.com/grafana/grafana) for visualization of the bot status and metrics
|
||||
- [Loki](https://github.com/grafana/loki) to visualize and query log files
|
||||
- [pgAdmin](https://github.com/postgres/pgadmin4) to view the database
|
||||
- [prometheus](https://github.com/prometheus/prometheus) for metric collection
|
||||
- [postgres](https://github.com/postgres/postgres) as a database
|
||||
- [loki](https://github.com/grafana/loki) for log aggregation
|
||||
|
||||
42
Tiltfile
Normal file
42
Tiltfile
Normal file
@@ -0,0 +1,42 @@
|
||||
allow_k8s_contexts('k8s-cluster')
|
||||
|
||||
load('ext://restart_process', 'docker_build_with_restart')
|
||||
registry = 'harbor.sheldan.dev/oneplus-bot/'
|
||||
abstracto_registry = 'harbor.sheldan.dev/abstracto/'
|
||||
|
||||
local_resource(
|
||||
'oneplus-bot-java-compile',
|
||||
'mvn install && ' +
|
||||
'rm -rf application/executable/target/jar-staging && ' +
|
||||
'unzip -o application/executable/target/oneplus-bot-exec.jar -d application/executable/target/jar-staging && ' +
|
||||
'rsync --delete --inplace --checksum -r application/executable/target/jar-staging/ application/executable/target/jar && ' +
|
||||
'mkdir application/executable/target/jar/snapshots && ' +
|
||||
'rsync --delete --inplace --checksum -r application/executable/target/jar/BOOT-INF/lib/*-SNAPSHOT.jar application/executable/target/jar/snapshots && ' +
|
||||
'rm -f application/executable/target/jar/BOOT-INF/lib/*-SNAPSHOT.jar ',
|
||||
deps=['pom.xml'])
|
||||
|
||||
docker_build_with_restart(
|
||||
registry + 'oneplus-bot-image',
|
||||
'./application/executable/target/jar',
|
||||
entrypoint=['java', '-noverify', '-cp', '.:./lib/*', 'dev.sheldan.oneplus.bot.executable.Application'],
|
||||
dockerfile='./application/executable/Dockerfile',
|
||||
live_update=[
|
||||
sync('./application/executable/target/jar/BOOT-INF/lib', '/app/lib'),
|
||||
sync('./application/executable/target/jar/META-INF', '/app/META-INF'),
|
||||
sync('./application/executable/target/jar/BOOT-INF/classes', '/app'),
|
||||
sync('./application/executable/target/jar/snapshots', '/app/lib')
|
||||
],
|
||||
)
|
||||
|
||||
docker_build(registry + 'oneplus-bot-db-data', 'deployment/image-packaging/src/main/docker/db-data/')
|
||||
docker_build(registry + 'oneplus-bot-template-data', 'deployment/image-packaging/src/main/docker/template-data/')
|
||||
docker_build(registry + 'oneplus-bot-private-rest-api', 'deployment/image-packaging/src/main/docker/private-rest-api/', build_args={'REGISTRY_PREFIX': abstracto_registry})
|
||||
|
||||
|
||||
k8s_yaml(helm('deployment/helm/oneplus-bot', values=
|
||||
['./../OnePlusBot-environments/argocd/apps/oneplus-bot/values/local/values.yaml',
|
||||
'secrets://./../OnePlusBot-environments/argocd/apps/oneplus-bot/values/local/values.secrets.yaml']
|
||||
))
|
||||
|
||||
local_resource('fetch-packages', 'mvn install -f deployment/image-packaging/pom.xml', auto_init=False, trigger_mode = TRIGGER_MODE_MANUAL)
|
||||
k8s_resource('chart-oneplus-bot', port_forwards='5005:5005')
|
||||
10
application/executable/Dockerfile
Normal file
10
application/executable/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM amazoncorretto:17.0.8-alpine3.18
|
||||
RUN apk add entr
|
||||
|
||||
WORKDIR /app
|
||||
ADD BOOT-INF/lib/ /app/lib
|
||||
ADD snapshots/ /app/lib
|
||||
ADD META-INF /app/META-INF
|
||||
ADD BOOT-INF/classes /app
|
||||
|
||||
ENTRYPOINT java -cp .:./lib/* dev.sheldan.oneplus.bot.executable.Application
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application</groupId>
|
||||
<artifactId>application</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>executable</artifactId>
|
||||
@@ -14,6 +14,7 @@
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>oneplus-bot</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -100,11 +101,36 @@
|
||||
<artifactId>starboard-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>modmail-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>voice-channel-context-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>logging-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>anti-raid-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>invite-filter-impl</artifactId>
|
||||
@@ -125,6 +151,16 @@
|
||||
<artifactId>experience-tracking-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>image-generation-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation-impl</artifactId>
|
||||
@@ -136,6 +172,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.custom</groupId>
|
||||
<artifactId>moderation-custom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<artifactId>news</artifactId>
|
||||
@@ -160,6 +202,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<artifactId>seasonal</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package dev.sheldan.oneplus.bot.executable;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/abstracto
|
||||
spring.datasource.username= abstracto
|
||||
spring.datasource.password= abstracto
|
||||
spring.jpa.properties.hibernate.default_schema=abstracto
|
||||
spring.quartz.jdbc.initialize-schema=never
|
||||
|
||||
spring.jpa.hibernate.ddl-auto = none
|
||||
|
||||
spring.jpa.show-sql = false
|
||||
|
||||
spring.jpa.properties.hibernate.format_sql = true
|
||||
log4j.logger.org.hibernate.SQL=trace
|
||||
log4j.logger.org.hibernate.type.descriptor.sql=trace
|
||||
log4j.logger.org.hibernate.type=trace
|
||||
|
||||
management.metrics.tags.application=oneplus-bot
|
||||
spring.security.user.name=abstracto
|
||||
spring.security.user.password=password
|
||||
spring.security.user.roles=USER
|
||||
|
||||
spring.application.name=OnePlusBot
|
||||
@@ -1,11 +1,14 @@
|
||||
spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||
spring.datasource.username= ${DB_USER}
|
||||
spring.datasource.password= ${DB_PASS}
|
||||
spring.jpa.hibernate.default_schema=${DB_NAME}
|
||||
spring.datasource.hikari.maximum-pool-size=${hikariPoolSize}
|
||||
spring.jpa.hibernate.default_schema=abstracto
|
||||
spring.jpa.properties.hibernate.default_schema=abstracto
|
||||
spring.quartz.jdbc.initialize-schema=never
|
||||
management.metrics.tags.application=oneplus-bot
|
||||
spring.security.user.name= ${REST_USER_NAME}
|
||||
spring.security.user.password= ${REST_PASSWORD}
|
||||
spring.security.user.roles=USER
|
||||
management.metrics.tags.application=OnePlusBot
|
||||
management.endpoint.health.probes.enabled=true
|
||||
management.health.livenessState.enabled=true
|
||||
management.health.readinessState.enabled=true
|
||||
spring.application.name=OnePlusBot
|
||||
|
||||
spring.application.name=OnePlusBot
|
||||
spring.main.allow-circular-references=true
|
||||
@@ -1,31 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.deployment</groupId>
|
||||
<artifactId>deployment</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.custom</groupId>
|
||||
<artifactId>oneplus-bot-customizations</artifactId>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>docker-compose</artifactId>
|
||||
<artifactId>dynamic-activity-custom</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/liquibase.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assembly-docker-compose-configuration</id>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/docker-compose.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -1,19 +1,18 @@
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
|
||||
<id>docker-compose</id>
|
||||
<id>liquibase</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>./docker-compose</outputDirectory>
|
||||
<directory>${project.basedir}/src/main/resources/</directory>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<directory>${project.basedir}/src/main/resources/migrations</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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="dynamic_activity-insertion">
|
||||
<insert tableName="activity">
|
||||
<column name="type" value="STREAMING"/>
|
||||
<column name="template_key" value="fans"/>
|
||||
</insert>
|
||||
<insert tableName="activity">
|
||||
<column name="type" value="STREAMING"/>
|
||||
<column name="template_key" value="help"/>
|
||||
</insert>
|
||||
<insert tableName="activity">
|
||||
<column name="type" value="STREAMING"/>
|
||||
<column name="template_key" value="modmail"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -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="activity.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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="1.5.1/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>oneplus-bot-customizations</artifactId>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.custom</groupId>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>moderation-custom</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation-int</artifactId>
|
||||
<version>${abstracto.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/liquibase.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
|
||||
<id>liquibase</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<directory>${project.basedir}/src/main/resources/migrations</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -0,0 +1,52 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.commands;
|
||||
|
||||
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.moderation.config.ModerationModuleDefinition;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.config.ModerationCustomFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.service.ModModeServiceBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class ModMode extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private ModModeServiceBean modModeServiceBean;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Boolean newState = (Boolean) commandContext.getParameters().getParameters().get(0);
|
||||
return modModeServiceBean.setModModeTo(commandContext.getGuild(), newState)
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter newStateParameter = Parameter.builder().name("newState").templated(true).type(Boolean.class).build();
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("modMode")
|
||||
.async(true)
|
||||
.module(ModerationModuleDefinition.MODERATION)
|
||||
.parameters(Collections.singletonList(newStateParameter))
|
||||
.help(helpInfo)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ModerationCustomFeatureDefinition.MODERATION_CUSTOM;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.PostTargetEnum;
|
||||
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureConfig;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.service.ModModeServiceBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Component
|
||||
public class ModerationCustomFeature implements FeatureConfig {
|
||||
|
||||
public static final String WARN_NOTIFICATION_THRESHOLD = "warnNotificationThreshold";
|
||||
|
||||
@Autowired
|
||||
private ModerationFeatureConfig moderationFeatureConfig;
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ModerationCustomFeatureDefinition.MODERATION_CUSTOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureConfig> getRequiredFeatures() {
|
||||
return Arrays.asList(moderationFeatureConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostTargetEnum> getRequiredPostTargets() {
|
||||
return Arrays.asList(ModerationCustomPostTarget.WARN_THRESHOLD_NOTIFICATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredSystemConfigKeys() {
|
||||
return Arrays.asList(ModModeServiceBean.MODMODE_ROLE_CONFIG_KEY,
|
||||
ModModeServiceBean.MODMODE_CHANGED_ROLE_COLOR_CONFIG_KEY, WARN_NOTIFICATION_THRESHOLD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ModerationCustomFeatureDefinition implements FeatureDefinition {
|
||||
MODERATION_CUSTOM("moderationCustom");
|
||||
|
||||
private String key;
|
||||
|
||||
ModerationCustomFeatureDefinition(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.PostTargetEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ModerationCustomPostTarget implements PostTargetEnum {
|
||||
WARN_THRESHOLD_NOTIFICATION("warnThresholdNotification");
|
||||
|
||||
private String key;
|
||||
|
||||
ModerationCustomPostTarget(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:moderation-custom.properties")
|
||||
public class ModerationCustomProperties {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
|
||||
|
||||
public class ModRoleNotFoundException extends AbstractoTemplatableException {
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "mod_role_not_found_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.ChannelDisplay;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.*;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.moderation.listener.WarningCreatedListener;
|
||||
import dev.sheldan.abstracto.moderation.model.listener.WarningCreatedEventModel;
|
||||
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.config.ModerationCustomFeature;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.config.ModerationCustomFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.config.ModerationCustomPostTarget;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.model.template.WarningThresholdNotificationModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class WarningAddedListener implements WarningCreatedListener {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private WarnManagementService warnManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
public static final String WARN_THRESHOLD_NOTIFICATION_TEMPLATE_KEY = "warning_threshold_notification";
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(WarningCreatedEventModel model) {
|
||||
Long warnNotificationAmount = configService.getLongValueOrConfigDefault(ModerationCustomFeature.WARN_NOTIFICATION_THRESHOLD, model.getServerId());
|
||||
ServerUser warnedUser = ServerUser
|
||||
.builder()
|
||||
.userId(model.getWarnedUserId())
|
||||
.serverId(model.getServerId())
|
||||
.build();
|
||||
AUserInAServer warnedUserInAServer = userInServerManagementService.loadOrCreateUser(warnedUser);
|
||||
List<Long> activeWarnsForUser = warnManagementService.getActiveWarnsForUser(warnedUserInAServer)
|
||||
.stream().map(warning -> warning.getWarnId().getId()).collect(Collectors.toList());
|
||||
Set<Long> warnIds = new HashSet<>(activeWarnsForUser);
|
||||
// we cant be sure we receive the newly persisted warning yet, sadly
|
||||
warnIds.add(model.getWarningId());
|
||||
if(warnIds.size() == warnNotificationAmount) {
|
||||
Long serverId = model.getServerId();
|
||||
|
||||
Long channelId = model.getWarningChannelId();
|
||||
Long warnedUserId = model.getWarnedUserId();
|
||||
GuildMessageChannel channel = channelService.getMessageChannelFromServer(serverId, channelId);
|
||||
WarningThresholdNotificationModel notificationModel = WarningThresholdNotificationModel
|
||||
.builder()
|
||||
.channelDisplay(ChannelDisplay.fromChannel(channel))
|
||||
.memberDisplay(MemberDisplay.fromAUserInAServer(warnedUserInAServer))
|
||||
.messageId(model.getWarningMessageId())
|
||||
.warnCount(warnIds.size())
|
||||
.build();
|
||||
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(WARN_THRESHOLD_NOTIFICATION_TEMPLATE_KEY, notificationModel, serverId);
|
||||
FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, ModerationCustomPostTarget.WARN_THRESHOLD_NOTIFICATION, serverId))
|
||||
.thenAccept(unused -> log.info("Warn threshold notification sent for user {} in server {}.", warnedUserId, serverId))
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to sent warn threshold notification for user {} in server {}.", warnedUserId, serverId, throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ModerationCustomFeatureDefinition.MODERATION_CUSTOM;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.ChannelDisplay;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class WarningThresholdNotificationModel {
|
||||
private MemberDisplay memberDisplay;
|
||||
private Integer warnCount;
|
||||
private ChannelDisplay channelDisplay;
|
||||
private Long messageId;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.sheldan.oneplus.bot.custom.moderation.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.oneplus.bot.custom.moderation.exception.ModRoleNotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ModModeServiceBean {
|
||||
public static final String MODMODE_ROLE_CONFIG_KEY = "modModeRoleId";
|
||||
public static final String MODMODE_CHANGED_ROLE_COLOR_CONFIG_KEY = "modModeNewRoleColor";
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
public CompletableFuture<Void> setModModeTo(Guild guild, Boolean newState) {
|
||||
if(Boolean.TRUE.equals(newState)) {
|
||||
return enableModMode(guild);
|
||||
} else {
|
||||
return disableModMoe(guild);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> enableModMode(Guild guild) {
|
||||
Color colorToSet = getColorFromConfig(MODMODE_CHANGED_ROLE_COLOR_CONFIG_KEY, guild);
|
||||
return setModRoleTo(guild, colorToSet);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> disableModMoe(Guild guild) {
|
||||
return setModRoleTo(guild, null);
|
||||
}
|
||||
|
||||
private Color getColorFromConfig(String key, Guild guild) {
|
||||
String colorString = configService.getStringValueOrConfigDefault(key, guild.getIdLong());
|
||||
String[] parts = colorString.split(",");
|
||||
return new Color(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> setModRoleTo(Guild guild, Color color) {
|
||||
Long roleId = configService.getLongValue(MODMODE_ROLE_CONFIG_KEY, guild.getIdLong());
|
||||
Role modRole = guild.getRoleById(roleId);
|
||||
if(modRole != null) {
|
||||
return modRole.getManager().setColor(color).submit();
|
||||
} else {
|
||||
throw new ModRoleNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?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="moderationCustomFeature" value="(SELECT id FROM feature WHERE key = 'moderationCustom')"/>
|
||||
<property name="moderationModule" value="(SELECT id FROM module WHERE name = 'moderation')"/>
|
||||
<changeSet author="Sheldan" id="moderationCustom_modmode-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="modMode"/>
|
||||
<column name="module_id" valueComputed="${moderationModule}"/>
|
||||
<column name="feature_id" valueComputed="${moderationCustomFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?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="feature.xml" relativeToChangelogFile="true"/>
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -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="moderation_custom_feature-insertion">
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="moderationCustom"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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="1.5.2/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,13 @@
|
||||
abstracto.featureFlags.moderationCustom.featureName=moderationCustom
|
||||
abstracto.featureFlags.moderationCustom.enabled=false
|
||||
|
||||
abstracto.systemConfigs.modModeRoleId.name=modModeRoleId
|
||||
abstracto.systemConfigs.modModeRoleId.longValue=0
|
||||
|
||||
abstracto.systemConfigs.modModeNewRoleColor.name=modModeNewRoleColor
|
||||
abstracto.systemConfigs.modModeNewRoleColor.stringValue=0,0,0
|
||||
|
||||
abstracto.systemConfigs.warnNotificationThreshold.name=warnNotificationThreshold
|
||||
abstracto.systemConfigs.warnNotificationThreshold.longValue=3
|
||||
|
||||
abstracto.postTargets.warnThresholdNotification.name=warnThresholdNotification
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application</groupId>
|
||||
<artifactId>application</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -13,5 +13,7 @@
|
||||
|
||||
<modules>
|
||||
<module>starboard-custom</module>
|
||||
<module>dynamic-activity-custom</module>
|
||||
<module>moderation-custom</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.custom</groupId>
|
||||
<artifactId>oneplus-bot-customizations</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>oneplus-bot-modules</artifactId>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ import dev.sheldan.oneplus.bot.modules.faq.config.FAQFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.config.FAQModuleDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.command.faq.FAQResponseModel;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.service.FAQResponseServiceBean;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -50,7 +51,7 @@ public class FAQ extends AbstractConditionableCommand {
|
||||
String commandName;
|
||||
if(!parameters.isEmpty()) {
|
||||
commandName = (String) parameters.get(0);
|
||||
TextChannel channel;
|
||||
GuildMessageChannel channel;
|
||||
if (parameters.size() == 2) {
|
||||
channel = (TextChannel) parameters.get(1);
|
||||
} else {
|
||||
@@ -104,7 +105,6 @@ public class FAQ extends AbstractConditionableCommand {
|
||||
.help(helpInfo)
|
||||
.async(true)
|
||||
.templated(true)
|
||||
.causesReaction(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ public class ImportFAQ extends AbstractConditionableCommand {
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
List<FaqCommandConfig> commands = faqServiceBean.loadFAQCommandsFromJson(jsonContent);
|
||||
faqServiceBean.createOrUpdateFAQCommands(commands, server);
|
||||
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
|
||||
} else {
|
||||
|
||||
List<String> errors = jsonValidationService.getDetailedException(result.getExceptions())
|
||||
@@ -73,8 +74,8 @@ public class ImportFAQ extends AbstractConditionableCommand {
|
||||
.map(ValidationException::getMessage)
|
||||
.collect(Collectors.toList());
|
||||
channelService.sendTextToChannel(String.join("\n", errors), commandContext.getChannel());
|
||||
return CompletableFuture.completedFuture(CommandResult.fromError("Incorrect faq config."));
|
||||
}
|
||||
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
|
||||
} catch (IOException e) {
|
||||
log.error("IO Exception when loading input file.", e);
|
||||
throw new AbstractoTemplatedException("Failed to load json config.", "failed_to_set_template_exception", e);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.oneplus.bot.modules.faq.converter;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.service.BotService;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.command.config.*;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.database.FAQChannelGroupCommand;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.database.FAQCommand;
|
||||
@@ -9,6 +10,7 @@ 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.stream.Collectors;
|
||||
|
||||
@@ -18,9 +20,16 @@ public class FAQCommandConfigConverter {
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private BotService botService;
|
||||
|
||||
public String serializeCommands(List<FAQCommand> asList) {
|
||||
Long botId = botService.getInstance().getSelfUser().getIdLong();
|
||||
asList.sort(Comparator.comparing(FAQCommand::getName));
|
||||
List<FaqCommandConfig> config = asList.stream().map(faqCommand -> {
|
||||
List<FaqCommandResponseConfig> commandResponseConfigs = convertGroupCommands(faqCommand.getGroupResponses());
|
||||
List<FAQChannelGroupCommand> responses = faqCommand.getGroupResponses();
|
||||
responses.sort(Comparator.comparing(groupCommand -> groupCommand.getChannelGroup().getChannelGroup().getGroupName()));
|
||||
List<FaqCommandResponseConfig> commandResponseConfigs = convertGroupCommands(responses, botId);
|
||||
List<String> aliases;
|
||||
if(faqCommand.getAliases() != null) {
|
||||
aliases = faqCommand.getAliases().stream().map(faqCommandAlias -> faqCommandAlias.getId().getAlias()).collect(Collectors.toList());
|
||||
@@ -39,9 +48,9 @@ public class FAQCommandConfigConverter {
|
||||
return gson.toJson(config);
|
||||
}
|
||||
|
||||
private List<FaqCommandResponseConfig> convertGroupCommands(List<FAQChannelGroupCommand> responses) {
|
||||
private List<FaqCommandResponseConfig> convertGroupCommands(List<FAQChannelGroupCommand> responses, Long botUserId) {
|
||||
return responses.stream().map(faqChannelGroupCommand -> {
|
||||
List<FaqCommandResponseMessageConfig> responseConfigs = convertCommandResponses(faqChannelGroupCommand.getResponses());
|
||||
List<FaqCommandResponseMessageConfig> responseConfigs = convertCommandResponses(faqChannelGroupCommand.getResponses(), botUserId);
|
||||
return FaqCommandResponseConfig
|
||||
.builder()
|
||||
.channelGroupName(faqChannelGroupCommand.getChannelGroup().getChannelGroup().getGroupName())
|
||||
@@ -50,13 +59,15 @@ public class FAQCommandConfigConverter {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<FaqCommandResponseMessageConfig> convertCommandResponses(List<FAQCommandResponse> responses) {
|
||||
return responses.stream().map(this::convertCommandResponse).collect(Collectors.toList());
|
||||
private List<FaqCommandResponseMessageConfig> convertCommandResponses(List<FAQCommandResponse> responses, Long botUserId) {
|
||||
return responses.stream().map(response -> convertCommandResponse(response, botUserId)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private FaqCommandResponseMessageConfig convertCommandResponse(FAQCommandResponse response) {
|
||||
private FaqCommandResponseMessageConfig convertCommandResponse(FAQCommandResponse response, Long botUserId) {
|
||||
FaqCommandResponseEmbedConfig embedConfig = null;
|
||||
if(response.getDescription() != null) {
|
||||
// one of those must not be null, for it to be considered a proper embed
|
||||
if(response.getDescription() != null || response.getImageURL() != null) {
|
||||
boolean useBot = response.getAuthorUserId().equals(botUserId);
|
||||
FaqCommandResponseEmbedColorConfig colorConfig = FaqCommandResponseEmbedColorConfig
|
||||
.builder()
|
||||
.red(response.getRed())
|
||||
@@ -65,8 +76,8 @@ public class FAQCommandConfigConverter {
|
||||
.build();
|
||||
FaqCommandResponseEmbedAuthorConfig authorConfig = FaqCommandResponseEmbedAuthorConfig
|
||||
.builder()
|
||||
.userId(response.getAuthorUserId())
|
||||
.useBot(null)
|
||||
.userId(useBot ? null : response.getAuthorUserId())
|
||||
.useBot(useBot)
|
||||
.build();
|
||||
embedConfig = FaqCommandResponseEmbedConfig
|
||||
.builder()
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.database.embed.ChannelGroupCommandId;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.database.embed.FAQCommandAliasId;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.models.database.embed.CommandResponseId;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database.embed;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database.embed;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.sheldan.oneplus.bot.modules.faq.models.database.embed;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
|
||||
@@ -22,10 +22,8 @@ import dev.sheldan.oneplus.bot.modules.faq.service.management.FAQChannelGroupCom
|
||||
import dev.sheldan.oneplus.bot.modules.faq.service.management.FAQCommandAliasManagementService;
|
||||
import dev.sheldan.oneplus.bot.modules.faq.service.management.FAQCommandManagementServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.ISnowflake;
|
||||
import net.dv8tion.jda.api.entities.SelfUser;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -67,7 +65,7 @@ public class FAQResponseServiceBean {
|
||||
@Autowired
|
||||
private FAQResponseServiceBean self;
|
||||
|
||||
public CompletableFuture<FAQResponseModel> loadFAQResponse(String commandName, TextChannel textChannel) {
|
||||
public CompletableFuture<FAQResponseModel> loadFAQResponse(String commandName, GuildMessageChannel textChannel) {
|
||||
AServer server = serverManagementService.loadServer(textChannel.getGuild().getIdLong());
|
||||
Optional<FAQCommand> faqCommandOptional = faqCommandManagementServiceBean.findByNameAndServer(commandName, server);
|
||||
if(!faqCommandOptional.isPresent()) {
|
||||
|
||||
@@ -3,143 +3,124 @@
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 30,
|
||||
"items": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"faqCommandName": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"faqCommandName": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 30,
|
||||
"pattern": "\\w*"
|
||||
},
|
||||
"global": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"aliases": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"maxItems": 20,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 30,
|
||||
"pattern": "\\w*"
|
||||
},
|
||||
"global": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"aliases": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 20,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 30,
|
||||
"pattern": "\\w*"
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 255,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channelGroupName": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 20,
|
||||
"pattern": "\\w*"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 3,
|
||||
"items": [
|
||||
{
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 255,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channelGroupName": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 20,
|
||||
"pattern": "\\w*"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 3,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"position": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"additionalMessage": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 2000
|
||||
},
|
||||
"embed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"position": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"additionalMessage": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 2000
|
||||
},
|
||||
"embed": {
|
||||
"imageUrl": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 2000,
|
||||
"pattern": "\\s*https?:\/\/\\S+"
|
||||
},
|
||||
"color": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 2000
|
||||
"red": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"imageUrl": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 2000,
|
||||
"pattern": "\\s*https?:\/\/\\S+"
|
||||
"green": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"color": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"red": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"green": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"blue": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"red",
|
||||
"green",
|
||||
"blue"
|
||||
]
|
||||
"blue": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"maximum": 255
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"red",
|
||||
"green",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"author": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"userId": {
|
||||
"minimum": 1,
|
||||
"maximum": 18446744073709551615,
|
||||
"type": "integer"
|
||||
},
|
||||
"author": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"userId": {
|
||||
"minimum": 1,
|
||||
"maximum": 18446744073709551615,
|
||||
"type": "integer"
|
||||
},
|
||||
"useBot": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"userId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"useBot"
|
||||
]
|
||||
}
|
||||
]
|
||||
"useBot": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"description",
|
||||
"author"
|
||||
"userId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"imageUrl",
|
||||
"author"
|
||||
"useBot"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -149,41 +130,56 @@
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"additionalMessage",
|
||||
"position"
|
||||
"description",
|
||||
"author"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"embed",
|
||||
"position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"additionalMessage",
|
||||
"embed",
|
||||
"position"
|
||||
"imageUrl",
|
||||
"author"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"additionalMessage",
|
||||
"position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"embed",
|
||||
"position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"additionalMessage",
|
||||
"embed",
|
||||
"position"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"channelGroupName",
|
||||
"messages"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"channelGroupName",
|
||||
"messages"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"faqCommandName",
|
||||
"responses"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"faqCommandName",
|
||||
"responses"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,22 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<artifactId>oneplus-bot-modules</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>news</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.scheduling</groupId>
|
||||
<artifactId>scheduling-int</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.util.List;
|
||||
@Component
|
||||
public class NewsFeature implements FeatureConfig {
|
||||
|
||||
public static final String NEWS_FORUM_POST_NOTIFICATION_SERVER_ID_ENV_NAME = "NEWS_FORUM_POST_NOTIFICATION_SERVER_ID";
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return NewsFeatureDefinition.NEWS;
|
||||
@@ -18,6 +20,6 @@ public class NewsFeature implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public List<PostTargetEnum> getRequiredPostTargets() {
|
||||
return Arrays.asList(NewsPostTarget.NEWS_TARGET);
|
||||
return Arrays.asList(NewsPostTarget.NEWS_TARGET, NewsPostTarget.FORUM_POST_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum NewsPostTarget implements PostTargetEnum {
|
||||
NEWS_TARGET("news");
|
||||
NEWS_TARGET("news"), FORUM_POST_NOTIFICATION("forumPostNotification");
|
||||
|
||||
private String key;
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.job;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.service.NewsSourceServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.PersistJobDataAfterExecution;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@DisallowConcurrentExecution
|
||||
@Component
|
||||
@PersistJobDataAfterExecution
|
||||
public class CheckForNewsPosts extends QuartzJobBean {
|
||||
|
||||
@Autowired
|
||||
private NewsSourceServiceBean newsSourceServiceBean;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
try {
|
||||
log.info("Executing news post check job.");
|
||||
newsSourceServiceBean.checkForNewThreads();
|
||||
} catch (Exception exception) {
|
||||
log.error("Failed to execute news post check job.", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.forum.ForumPost;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class ForumPostNotificationEntry {
|
||||
private Long postId;
|
||||
private String subject;
|
||||
private String content;
|
||||
private Long creatorId;
|
||||
|
||||
public static ForumPostNotificationEntry fromPost(ForumPost forumPost) {
|
||||
return ForumPostNotificationEntry
|
||||
.builder()
|
||||
.postId(forumPost.getId())
|
||||
.subject(forumPost.getSubject())
|
||||
.content(forumPost.getContent())
|
||||
.creatorId(forumPost.getSource().getUserId())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ForumPostNotificationModel {
|
||||
private List<ForumPostNotificationEntry> entries;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.database;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "news_forum_post")
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class NewsForumPost {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "creator_id", nullable = false)
|
||||
private NewsSource creator;
|
||||
|
||||
@Column(name = "created")
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated")
|
||||
private Instant updated;
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.database;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "news_source")
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class NewsSource {
|
||||
@Id
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
|
||||
@Column(name = "thread_count")
|
||||
private Long threadCount;
|
||||
|
||||
@Column(name = "created")
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated")
|
||||
private Instant updated;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ForumPost {
|
||||
private Long id;
|
||||
private String subject;
|
||||
private String content;
|
||||
private NewsSource source;
|
||||
|
||||
public static ForumPost fromRow(NewsForumPostDataRow dataRow, NewsSource newsSource) {
|
||||
return ForumPost
|
||||
.builder()
|
||||
.subject(dataRow.getSubject())
|
||||
.id(dataRow.getId())
|
||||
.content(dataRow.getContent())
|
||||
.source(newsSource)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class NewsForumPostData {
|
||||
@SerializedName("rows")
|
||||
private List<NewsForumPostDataRow> rows;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class NewsForumPostDataRow {
|
||||
@SerializedName("id")
|
||||
private Long id;
|
||||
|
||||
@SerializedName("subject")
|
||||
private String subject;
|
||||
|
||||
@SerializedName("content")
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class NewsForumPostResponse {
|
||||
|
||||
@SerializedName("data")
|
||||
private NewsForumPostData newsForumPostData;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class NewsSourceResponse {
|
||||
@SerializedName("data")
|
||||
private NewsSourceUserData user;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class NewsSourceUserData {
|
||||
@SerializedName("userStatVO")
|
||||
private NewsSourceUserStats userStats;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.model.forum;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class NewsSourceUserStats {
|
||||
@SerializedName("threadCount")
|
||||
private Long threadCount;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.repository;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsForumPost;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface NewsForumPostRepository extends JpaRepository<NewsForumPost, Long> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.repository;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface NewsResourceRepository extends JpaRepository<NewsSource, Long> {
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.service;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.forum.ForumPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.forum.NewsForumPostResponse;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.forum.NewsSourceResponse;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class ForumApiClient {
|
||||
|
||||
@Autowired
|
||||
private OkHttpClient okHttpClient;
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Value("${abstracto.feature.news.userURL}")
|
||||
private String userRequestURL;
|
||||
|
||||
@Value("${abstracto.feature.news.threadURL}")
|
||||
private String threadInfoUrl;
|
||||
|
||||
public Long getCurrentThreadCount(NewsSource newsSource) {
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format(userRequestURL, newsSource.getUserId()))
|
||||
.get()
|
||||
.build();
|
||||
Response response;
|
||||
try {
|
||||
response = okHttpClient.newCall(request).execute();
|
||||
if(!response.isSuccessful()) {
|
||||
throw new AbstractoRunTimeException(String.format("Failed to load user info for id %s", newsSource.getUserId()));
|
||||
}
|
||||
NewsSourceResponse newsSourceResponse = gson.fromJson(response.body().string(), NewsSourceResponse.class);
|
||||
if (newsSourceResponse.getUser() != null
|
||||
&& newsSourceResponse.getUser().getUserStats() != null
|
||||
&& newsSourceResponse.getUser().getUserStats().getThreadCount() != null) {
|
||||
return newsSourceResponse.getUser().getUserStats().getThreadCount();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new AbstractoRunTimeException(e);
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public List<ForumPost> getPostsOfSource(NewsSource source) {
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format(threadInfoUrl, source.getUserId()))
|
||||
.get()
|
||||
.build();
|
||||
Response response;
|
||||
try {
|
||||
response = okHttpClient.newCall(request).execute();
|
||||
if(!response.isSuccessful()) {
|
||||
throw new AbstractoRunTimeException(String.format("Failed to load thread info for id %s", source.getUserId()));
|
||||
}
|
||||
NewsForumPostResponse newsSourceResponse = gson.fromJson(response.body().string(), NewsForumPostResponse.class);
|
||||
if (newsSourceResponse.getNewsForumPostData() != null
|
||||
&& newsSourceResponse.getNewsForumPostData().getRows() != null) {
|
||||
return newsSourceResponse
|
||||
.getNewsForumPostData()
|
||||
.getRows()
|
||||
.stream()
|
||||
.map(dataRow -> ForumPost.fromRow(dataRow, source))
|
||||
.toList();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new AbstractoRunTimeException(e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import dev.sheldan.oneplus.bot.modules.news.model.database.NewsPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.service.management.NewsPostManagementServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -113,7 +113,7 @@ public class NewsServiceBean {
|
||||
log.info("Updating news post {} with new content based on message from user {} in server {}.",
|
||||
newsPost.getSourceMessageId(), updatedMessage.getIdLong(), updatedMessage.getGuild().getId());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MESSAGE_TEMPLATE_KEY, model, serverId);
|
||||
TextChannel newsChannel = channelService.getTextChannelFromServer(serverId, newsPost.getNewsChannel().getId());
|
||||
GuildMessageChannel newsChannel = channelService.getMessageChannelFromServer(serverId, newsPost.getNewsChannel().getId());
|
||||
return channelService.editMessageInAChannelFuture(messageToSend, newsChannel, newsPost.getNewsMessageId())
|
||||
.thenApply(message -> null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.service.PostTargetService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.oneplus.bot.modules.news.config.NewsPostTarget;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.ForumPostNotificationEntry;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.ForumPostNotificationModel;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsForumPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.forum.ForumPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.service.management.NewsForumPostManagementServiceBean;
|
||||
import dev.sheldan.oneplus.bot.modules.news.service.management.NewsSourceManagementServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.sheldan.oneplus.bot.modules.news.config.NewsFeature.NEWS_FORUM_POST_NOTIFICATION_SERVER_ID_ENV_NAME;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class NewsSourceServiceBean {
|
||||
|
||||
@Autowired
|
||||
private ForumApiClient forumApiClient;
|
||||
|
||||
@Autowired
|
||||
private NewsSourceManagementServiceBean newsSourceManagementServiceBean;
|
||||
|
||||
@Autowired
|
||||
private NewsForumPostManagementServiceBean newsForumPostManagementServiceBean;
|
||||
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private NewsSourceServiceBean self;
|
||||
|
||||
private static final String NEWS_FORUM_POST_NOTIFICATION_TEMPLATE_KEY = "newsForumPost_notification";
|
||||
|
||||
public void checkForNewThreads() {
|
||||
Long targetServerId = Long.parseLong(System.getenv(NEWS_FORUM_POST_NOTIFICATION_SERVER_ID_ENV_NAME));
|
||||
List<ForumPost> newForumPosts = getNewForumPosts();
|
||||
log.info("Found {} new forum posts.", newForumPosts.size());
|
||||
if(newForumPosts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<ForumPostNotificationEntry> entries = new ArrayList<>();
|
||||
newForumPosts.forEach(forumPost -> entries.add(ForumPostNotificationEntry.fromPost(forumPost)));
|
||||
|
||||
ForumPostNotificationModel model = ForumPostNotificationModel
|
||||
.builder()
|
||||
.entries(entries)
|
||||
.build();
|
||||
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(NEWS_FORUM_POST_NOTIFICATION_TEMPLATE_KEY, model, targetServerId);
|
||||
|
||||
FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, NewsPostTarget.FORUM_POST_NOTIFICATION, targetServerId))
|
||||
.thenAccept(unused -> {
|
||||
log.info("Sent news forum post notification.");
|
||||
self.persistForumPostsAndThreadCount(entries);
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to send news forum post notification.", throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void persistForumPostsAndThreadCount(List<ForumPostNotificationEntry> entries) {
|
||||
Map<Long, NewsSource> sourceMap = newsSourceManagementServiceBean.loadNewsSources()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(NewsSource::getUserId, Function.identity()));
|
||||
|
||||
entries.forEach(forumPostNotificationEntry ->
|
||||
newsForumPostManagementServiceBean.createPost(sourceMap.get(forumPostNotificationEntry.getCreatorId()), forumPostNotificationEntry.getPostId()));
|
||||
|
||||
sourceMap.values().forEach(newsSource -> {
|
||||
Long currentThreadCount = forumApiClient.getCurrentThreadCount(newsSource);
|
||||
newsSource.setThreadCount(currentThreadCount);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean hasThreadCountChanged(NewsSource newsSource) {
|
||||
Long currentThreadCount = forumApiClient.getCurrentThreadCount(newsSource);
|
||||
return !currentThreadCount.equals(newsSource.getThreadCount());
|
||||
}
|
||||
|
||||
private List<ForumPost> getNewForumPosts() {
|
||||
List<NewsSource> newsSources = newsSourceManagementServiceBean.loadNewsSources();
|
||||
log.info("Total news source count: {}", newsSources.size());
|
||||
List<NewsSource> sourcesWithChangedThreadCount = newsSources
|
||||
.stream()
|
||||
.filter(this::hasThreadCountChanged)
|
||||
.toList();
|
||||
|
||||
log.info("News sources with new thread count: {}", sourcesWithChangedThreadCount.size());
|
||||
|
||||
List<ForumPost> currentForumPosts = sourcesWithChangedThreadCount
|
||||
.stream()
|
||||
.map(newsSource -> forumApiClient.getPostsOfSource(newsSource))
|
||||
.flatMap(Collection::stream)
|
||||
.toList();
|
||||
|
||||
log.info("Total amount of incoming forum posts: {}", currentForumPosts.size());
|
||||
if(currentForumPosts.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Set<Long> incomingForumPostIds = currentForumPosts
|
||||
.stream()
|
||||
.map(ForumPost::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<NewsForumPost> existingNewsForumPosts = newsForumPostManagementServiceBean.getAllPosts();
|
||||
|
||||
log.info("Total amount of existing and tracked forum posts: {}", existingNewsForumPosts.size());
|
||||
|
||||
Set<Long> existingForumPostIds = existingNewsForumPosts
|
||||
.stream()
|
||||
.map(NewsForumPost::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
incomingForumPostIds.removeAll(existingForumPostIds);
|
||||
|
||||
if(incomingForumPostIds.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Map<Long, ForumPost> incomingPostMap = currentForumPosts
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ForumPost::getId, Function.identity()));
|
||||
|
||||
return incomingForumPostIds.stream().map(incomingPostMap::get).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.service.management;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsForumPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import dev.sheldan.oneplus.bot.modules.news.repository.NewsForumPostRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class NewsForumPostManagementServiceBean {
|
||||
|
||||
@Autowired
|
||||
private NewsForumPostRepository repository;
|
||||
|
||||
public List<NewsForumPost> getAllPosts() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
public NewsForumPost createPost(NewsSource creator, Long id) {
|
||||
NewsForumPost post = NewsForumPost
|
||||
.builder()
|
||||
.creator(creator)
|
||||
.id(id)
|
||||
.build();
|
||||
return repository.save(post);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi
|
||||
import dev.sheldan.oneplus.bot.modules.news.exception.NewsPostNotFoundException;
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsPost;
|
||||
import dev.sheldan.oneplus.bot.modules.news.repository.NewsPostRepository;
|
||||
import jakarta.persistence.*;
|
||||
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 javax.persistence.EntityManager;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.oneplus.bot.modules.news.service.management;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.news.model.database.NewsSource;
|
||||
import dev.sheldan.oneplus.bot.modules.news.repository.NewsResourceRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class NewsSourceManagementServiceBean {
|
||||
|
||||
@Autowired
|
||||
private NewsResourceRepository newsResourceRepository;
|
||||
|
||||
public List<NewsSource> loadNewsSources() {
|
||||
return newsResourceRepository.findAll();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?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="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -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="news_check_job.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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="check_for_news_job-insert">
|
||||
<insert tableName="scheduler_job">
|
||||
<column name="name" value="checkForNewsJob"/>
|
||||
<column name="group_name" value="news"/>
|
||||
<column name="clazz" value="dev.sheldan.oneplus.bot.modules.news.job.CheckForNewsPosts"/>
|
||||
<column name="active" value="true"/>
|
||||
<column name="cron_expression" value="0 0 0 * * ?"/>
|
||||
<column name="recovery" value="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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="news_forum_post-table">
|
||||
<createTable tableName="news_forum_post">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="true" primaryKey="true" primaryKeyName="pk_news_forum_post"/>
|
||||
</column>
|
||||
<column name="creator_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint baseColumnNames="creator_id" baseTableName="news_forum_post" constraintName="fk_news_forum_post_creator"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="user_id" referencedTableName="news_source" validate="true"/>
|
||||
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS news_forum_post_update_trigger ON news_forum_post;
|
||||
CREATE TRIGGER repost_check_channel_group_update_trigger BEFORE UPDATE ON news_forum_post FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS news_forum_post_insert_trigger ON news_forum_post;
|
||||
CREATE TRIGGER repost_check_channel_group_insert_trigger BEFORE INSERT ON news_forum_post FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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="news_source-table">
|
||||
<createTable tableName="news_source">
|
||||
<column name="user_id" type="BIGINT">
|
||||
<constraints nullable="true" primaryKey="true" primaryKeyName="pk_news_source"/>
|
||||
</column>
|
||||
<column name="thread_count" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
</createTable>
|
||||
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS news_source_update_trigger ON news_source;
|
||||
CREATE TRIGGER repost_check_channel_group_update_trigger BEFORE UPDATE ON news_source FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS news_source_insert_trigger ON news_source;
|
||||
CREATE TRIGGER repost_check_channel_group_insert_trigger BEFORE INSERT ON news_source FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?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="news_source.xml" relativeToChangelogFile="true"/>
|
||||
<include file="news_forum_post.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -8,4 +8,5 @@
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="1.3.9-news/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.3.10-news/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.6.11/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -1,7 +1,12 @@
|
||||
abstracto.postTargets.news.name=news
|
||||
abstracto.postTargets.forumPostNotification.name=forumPostNotification
|
||||
|
||||
abstracto.featureFlags.news.featureName=news
|
||||
abstracto.featureFlags.news.enabled=false
|
||||
|
||||
abstracto.feature.news.removalDays=4
|
||||
abstracto.feature.news.postLockSeconds=3600
|
||||
|
||||
abstracto.feature.news.userURL=https://community.oneplus.com/ajax/user/frontend/user/info?uid=%s
|
||||
# TODO support pagination.. eventually
|
||||
abstracto.feature.news.threadURL=https://community.oneplus.com/ajax/user/frontend/thread/page?page=1&limit=1000&uid=%s
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application</groupId>
|
||||
<artifactId>application</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<module>setup</module>
|
||||
<module>referral</module>
|
||||
<module>faq</module>
|
||||
<module>seasonal</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<artifactId>oneplus-bot-modules</artifactId>
|
||||
<version>1.4.4</version>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
39
application/oneplus-bot-modules/seasonal/pom.xml
Normal file
39
application/oneplus-bot-modules/seasonal/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>dev.sheldan.oneplus.bot.application.modules</groupId>
|
||||
<artifactId>oneplus-bot-modules</artifactId>
|
||||
<version>1.6.14</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>seasonal</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/liquibase.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
|
||||
<id>liquibase</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<directory>${project.basedir}/src/main/resources/migrations</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.config.ModuleInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SeasonalEntertainmentFeatureDefinition implements ModuleDefinition {
|
||||
public static final String ENTERTAINMENT = "entertainment";
|
||||
|
||||
@Override
|
||||
public ModuleInfo getInfo() {
|
||||
return ModuleInfo
|
||||
.builder()
|
||||
.name(ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentModule() {
|
||||
return "default";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum SeasonalFeatureDefinition implements FeatureDefinition {
|
||||
LIGHTS("lights");
|
||||
|
||||
private String key;
|
||||
|
||||
SeasonalFeatureDefinition(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:seasonal.properties")
|
||||
public class SeasonalProperties {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.lights.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.exception.EntityGuildMismatchException;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalEntertainmentFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.lights.service.LightsRoleServiceBean;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class AddRoleToLights extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private LightsRoleServiceBean lightsMemberServiceBean;
|
||||
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Role role = (Role) parameters.get(0);
|
||||
if(!role.getGuild().equals(commandContext.getGuild())) {
|
||||
throw new EntityGuildMismatchException();
|
||||
}
|
||||
lightsMemberServiceBean.addMemberToSeasonalLights(role);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("role").templated(true).type(Role.class).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("addRoleToLights")
|
||||
.module(SeasonalEntertainmentFeatureDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SeasonalFeatureDefinition.LIGHTS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.lights.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.exception.EntityGuildMismatchException;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalEntertainmentFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.lights.service.LightsRoleServiceBean;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class RemoveRoleFromLights extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private LightsRoleServiceBean lightsMemberServiceBean;
|
||||
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Role role = (Role) parameters.get(0);
|
||||
if(!role.getGuild().equals(commandContext.getGuild())) {
|
||||
throw new EntityGuildMismatchException();
|
||||
}
|
||||
lightsMemberServiceBean.removeMemberFromSeasonalLights(role);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("role").templated(true).type(Role.class).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("removeRoleFromLights")
|
||||
.module(SeasonalEntertainmentFeatureDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SeasonalFeatureDefinition.LIGHTS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.lights.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.oneplus.bot.modules.seasonal.config.SeasonalEntertainmentFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalFeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.lights.service.LightsRoleServiceBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class SwitchLights extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private LightsRoleServiceBean lightsMemberServiceBean;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
return lightsMemberServiceBean.switchLights(commandContext.getGuild())
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("switchLights")
|
||||
.module(SeasonalEntertainmentFeatureDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.causesReaction(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SeasonalFeatureDefinition.LIGHTS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.lights.config;
|
||||
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.lights.models.LightsRoleColor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "abstracto.feature.lights")
|
||||
public class LightsColorConfig {
|
||||
private List<LightsRoleColor> colors;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.oneplus.bot.modules.seasonal.lights.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.oneplus.bot.modules.seasonal.config.SeasonalFeatureDefinition;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class LightsFeatureConfig implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SeasonalFeatureDefinition.LIGHTS;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user