├── .envrc ├── tooling ├── .gitignore ├── example.env └── lang_mapper.json ├── docker ├── config │ └── .gitignore ├── docker-compose.yml ├── Dockerfile └── dev.docker-compose.yml ├── docs ├── _config.yml ├── resources │ ├── answer.png │ ├── embed.png │ ├── fuzzy.png │ ├── mention.png │ ├── profile.png │ ├── roles.png │ └── reaction.png ├── invite.md ├── commands.md ├── setup.md └── metrics.md ├── src ├── main │ ├── resources │ │ ├── version │ │ ├── database │ │ │ ├── version │ │ │ └── postgresql │ │ │ │ └── 1 │ │ │ │ ├── patch_34.sql │ │ │ │ ├── patch_37.sql │ │ │ │ ├── patch_2.sql │ │ │ │ ├── patch_30.sql │ │ │ │ ├── patch_31.sql │ │ │ │ ├── patch_32.sql │ │ │ │ ├── patch_14.sql │ │ │ │ ├── patch_33.sql │ │ │ │ ├── patch_36.sql │ │ │ │ ├── patch_28.sql │ │ │ │ ├── patch_17.sql │ │ │ │ ├── patch_12.sql │ │ │ │ ├── patch_3.sql │ │ │ │ ├── patch_25.sql │ │ │ │ └── patch_4.sql │ │ └── Thankswords.json │ └── java │ │ └── de │ │ └── chojo │ │ └── repbot │ │ ├── web │ │ ├── routes │ │ │ └── RoutesBuilder.java │ │ ├── error │ │ │ └── ApiException.java │ │ └── Api.java │ │ ├── analyzer │ │ └── results │ │ │ ├── ResultType.java │ │ │ ├── match │ │ │ ├── ThankType.java │ │ │ ├── DirectAnalyzerResult.java │ │ │ └── fuzzy │ │ │ │ └── MemberMatch.java │ │ │ └── empty │ │ │ ├── EmptyResultReason.java │ │ │ └── EmptyAnalyzerResult.java │ │ ├── commands │ │ ├── reactions │ │ │ └── util │ │ │ │ ├── CheckResult.java │ │ │ │ └── EmojiCheckResult.java │ │ ├── setup │ │ │ └── handler │ │ │ │ └── NewStart.java │ │ ├── invite │ │ │ ├── Invite.java │ │ │ └── handler │ │ │ │ └── Show.java │ │ ├── dashboard │ │ │ └── Dashboard.java │ │ ├── debug │ │ │ └── Debug.java │ │ ├── bot │ │ │ └── handler │ │ │ │ ├── entitlement │ │ │ │ ├── Delete.java │ │ │ │ └── Show.java │ │ │ │ ├── InvalidateCache.java │ │ │ │ ├── Leave.java │ │ │ │ ├── system │ │ │ │ ├── Status.java │ │ │ │ ├── Reload.java │ │ │ │ ├── Restart.java │ │ │ │ ├── Shudown.java │ │ │ │ └── Upgrade.java │ │ │ │ ├── Redeploy.java │ │ │ │ ├── log │ │ │ │ └── Analyzer.java │ │ │ │ └── Search.java │ │ ├── messages │ │ │ └── Messages.java │ │ ├── gdpr │ │ │ ├── Gdpr.java │ │ │ └── handler │ │ │ │ ├── Delete.java │ │ │ │ └── Request.java │ │ ├── top │ │ │ └── Top.java │ │ ├── locale │ │ │ ├── handler │ │ │ │ ├── Reset.java │ │ │ │ └── List.java │ │ │ └── Locale.java │ │ ├── supporter │ │ │ └── handler │ │ │ │ ├── Refresh.java │ │ │ │ └── BaseSupporter.java │ │ ├── channel │ │ │ └── handler │ │ │ │ ├── log │ │ │ │ └── LogDisable.java │ │ │ │ ├── systemchannel │ │ │ │ ├── SystemChannelDisable.java │ │ │ │ └── SystemChannelEnable.java │ │ │ │ ├── autopost │ │ │ │ ├── AutopostDisable.java │ │ │ │ └── AutopostRefresh.java │ │ │ │ └── announcement │ │ │ │ ├── AnnouncementState.java │ │ │ │ └── AnnouncementLocation.java │ │ ├── repsettings │ │ │ └── handler │ │ │ │ └── name │ │ │ │ └── Reset.java │ │ ├── repadmin │ │ │ └── handler │ │ │ │ ├── resetdate │ │ │ │ ├── RemoveResetDate.java │ │ │ │ └── SetResetDateNow.java │ │ │ │ ├── reputation │ │ │ │ ├── Add.java │ │ │ │ ├── Set.java │ │ │ │ └── Remove.java │ │ │ │ └── Profile.java │ │ ├── ranking │ │ │ └── handler │ │ │ │ ├── guild │ │ │ │ ├── GuildGiven.java │ │ │ │ └── GuildReceived.java │ │ │ │ └── user │ │ │ │ ├── UserGiven.java │ │ │ │ └── UserReceived.java │ │ ├── scan │ │ │ └── handler │ │ │ │ └── Cancel.java │ │ ├── profile │ │ │ └── Profile.java │ │ ├── abuseprotection │ │ │ └── handler │ │ │ │ ├── cooldown │ │ │ │ ├── OnceCooldown.java │ │ │ │ └── SetCooldown.java │ │ │ │ └── message │ │ │ │ └── MaxMessageAge.java │ │ ├── roles │ │ │ └── handler │ │ │ │ ├── donor │ │ │ │ ├── AddDonor.java │ │ │ │ └── RemoveDonor.java │ │ │ │ └── receiver │ │ │ │ ├── AddReceiver.java │ │ │ │ └── RemoveReceiver.java │ │ ├── prune │ │ │ ├── handler │ │ │ │ └── Guild.java │ │ │ └── Prune.java │ │ ├── info │ │ │ └── Info.java │ │ └── thankwords │ │ │ └── handler │ │ │ └── List.java │ │ ├── dao │ │ ├── snapshots │ │ │ ├── statistics │ │ │ │ ├── ChartProvider.java │ │ │ │ ├── CommandStatistic.java │ │ │ │ ├── UserStatistic.java │ │ │ │ ├── builder │ │ │ │ │ └── LabeledCountStatisticBuilder.java │ │ │ │ ├── CountStatistics.java │ │ │ │ └── DowStatistics.java │ │ │ ├── GuildReputationStats.java │ │ │ ├── SubmitResultEntry.java │ │ │ ├── analyzer │ │ │ │ ├── ResultSnapshot.java │ │ │ │ └── match │ │ │ │ │ └── MatchResultSnapshot.java │ │ │ ├── ChannelStats.java │ │ │ └── ResultEntry.java │ │ ├── components │ │ │ ├── UserHolder.java │ │ │ ├── GuildHolder.java │ │ │ └── MemberHolder.java │ │ ├── access │ │ │ ├── guild │ │ │ │ ├── settings │ │ │ │ │ └── sub │ │ │ │ │ │ ├── CooldownDirection.java │ │ │ │ │ │ ├── autopost │ │ │ │ │ │ ├── RefreshType.java │ │ │ │ │ │ └── RefreshInterval.java │ │ │ │ │ │ └── thanking │ │ │ │ │ │ ├── DonorRoles.java │ │ │ │ │ │ └── ReceiverRoles.java │ │ │ │ ├── subscriptions │ │ │ │ │ ├── SkuTarget.java │ │ │ │ │ └── SubscriptionError.java │ │ │ │ ├── reputation │ │ │ │ │ └── sub │ │ │ │ │ │ └── ranking │ │ │ │ │ │ ├── RankingType.java │ │ │ │ │ │ ├── RankingScope.java │ │ │ │ │ │ └── UserRankings.java │ │ │ │ └── RepGuildId.java │ │ │ └── Cleanup.java │ │ ├── pagination │ │ │ ├── GuildList.java │ │ │ ├── ReputationLogAccess.java │ │ │ └── Ranking.java │ │ └── provider │ │ │ └── Metrics.java │ │ ├── statistic │ │ ├── EmbedDisplay.java │ │ ├── ReplacementProvider.java │ │ ├── element │ │ │ ├── ShardStatistic.java │ │ │ ├── GlobalShardStatistic.java │ │ │ └── ShardCountStatistic.java │ │ └── display │ │ │ ├── SystemInfoStatisticDisplay.java │ │ │ └── GlobalInfoStatisticDisplay.java │ │ ├── config │ │ ├── elements │ │ │ ├── sku │ │ │ │ ├── feature │ │ │ │ │ ├── ChannelBlacklist.java │ │ │ │ │ ├── LogChannel.java │ │ │ │ │ ├── Autopost.java │ │ │ │ │ ├── DetailedProfile.java │ │ │ │ │ ├── AdditionalEmojis.java │ │ │ │ │ ├── AdvancedRankings.java │ │ │ │ │ ├── Nickname.java │ │ │ │ │ ├── LocaleOverrides.java │ │ │ │ │ ├── AnalyzerLog.java │ │ │ │ │ ├── ReputationChannel.java │ │ │ │ │ ├── ReputationCategories.java │ │ │ │ │ └── ReputationLog.java │ │ │ │ ├── SKUEntry.java │ │ │ │ └── Subscription.java │ │ │ ├── Api.java │ │ │ ├── AnalyzerSettings.java │ │ │ ├── MagicImage.java │ │ │ ├── BaseSettings.java │ │ │ ├── Badges.java │ │ │ ├── Links.java │ │ │ ├── Database.java │ │ │ ├── Cleanup.java │ │ │ ├── SKU.java │ │ │ └── SelfCleanup.java │ │ ├── jackson │ │ │ ├── BotModule.java │ │ │ ├── serializer │ │ │ │ └── SKUEntrySerializer.java │ │ │ └── deserializer │ │ │ │ └── SKUEntryDeserializer.java │ │ └── exception │ │ │ └── ConfigurationException.java │ │ ├── listener │ │ ├── voting │ │ │ └── VoteComponent.java │ │ └── VoiceStateListener.java │ │ ├── util │ │ ├── Roles.java │ │ ├── Guilds.java │ │ ├── QueryLoader.java │ │ ├── Parser.java │ │ ├── LogNotify.java │ │ └── FilterUtil.java │ │ ├── service │ │ ├── RoleAccessException.java │ │ ├── OnboardingService.java │ │ ├── reputation │ │ │ ├── SubmitResult.java │ │ │ └── SubmitResultType.java │ │ ├── AnalyzerService.java │ │ ├── MonitorService.java │ │ └── MetricService.java │ │ ├── serialization │ │ └── ThankwordsContainer.java │ │ ├── actions │ │ ├── messages │ │ │ └── log │ │ │ │ ├── handler │ │ │ │ └── MessageAnalyzer.java │ │ │ │ └── MessageLog.java │ │ └── user │ │ │ ├── received │ │ │ ├── handler │ │ │ │ └── ReceivedReputation.java │ │ │ └── UserReceived.java │ │ │ └── donated │ │ │ └── received │ │ │ ├── handler │ │ │ └── DonatedReputation.java │ │ │ └── UserDonated.java │ │ ├── exceptions │ │ └── MissingSupportTier.java │ │ ├── core │ │ └── Shutdown.java │ │ └── ReputationBot.java └── test │ └── java │ └── de │ └── chojo │ └── repbot │ ├── commands │ └── ThankwordsTest.java │ ├── dao │ ├── pagination │ │ └── PageAccessTest.java │ └── access │ │ └── guild │ │ └── reputation │ │ └── sub │ │ └── AnalyzerTest.java │ └── TestScratch.java ├── tags ├── faq.md ├── remove_reputation.md ├── roles.md ├── analyzer_log.md ├── emojis.md ├── prune.md ├── request_data.md ├── delete_data.md ├── no_reputation.md └── context.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── mkdocs-setup ├── HEADER.txt ├── shell.nix ├── crowdin.yml ├── Pipfile ├── .github ├── renovate.json ├── workflows │ └── docs.yml ├── FUNDING.yml ├── krile.yaml ├── pull_request_template.md └── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md ├── .gitignore ├── CONTRIBUTING.md └── README.md /.envrc: -------------------------------------------------------------------------------- 1 | use nix 2 | -------------------------------------------------------------------------------- /tooling/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /tooling/example.env: -------------------------------------------------------------------------------- 1 | DEEPL_API_KEY= 2 | -------------------------------------------------------------------------------- /docker/config/.gitignore: -------------------------------------------------------------------------------- 1 | config.json 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /src/main/resources/version: -------------------------------------------------------------------------------- 1 | ${version} 2 | -------------------------------------------------------------------------------- /src/main/resources/database/version: -------------------------------------------------------------------------------- 1 | 1.37 2 | -------------------------------------------------------------------------------- /tooling/lang_mapper.json: -------------------------------------------------------------------------------- 1 | { 2 | "es_ES": "ES" 3 | } 4 | -------------------------------------------------------------------------------- /docs/resources/answer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/answer.png -------------------------------------------------------------------------------- /docs/resources/embed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/embed.png -------------------------------------------------------------------------------- /docs/resources/fuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/fuzzy.png -------------------------------------------------------------------------------- /docs/resources/mention.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/mention.png -------------------------------------------------------------------------------- /docs/resources/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/profile.png -------------------------------------------------------------------------------- /docs/resources/roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/roles.png -------------------------------------------------------------------------------- /docs/resources/reaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/docs/resources/reaction.png -------------------------------------------------------------------------------- /tags/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | The faq can be found on our [website](https://rainbowdashlabs.github.io/reputation-bot/faq/) 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbowdashlabs/reputation-bot/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_34.sql: -------------------------------------------------------------------------------- 1 | UPDATE repbot_schema.reputation_log SET donor_id = NULL WHERE donor_id = 0; 2 | -------------------------------------------------------------------------------- /mkdocs-setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | pip install mkdocs-material 3 | pip install mkdocs-git-revision-date-localized-plugin 4 | mkdocs serve 5 | -------------------------------------------------------------------------------- /HEADER.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {}, ... }: 2 | 3 | pkgs.mkShell { 4 | packages = with pkgs; [jdk21 python314 pipenv]; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_37.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.guild_settings 2 | ALTER COLUMN reset_date TYPE TIMESTAMP; 3 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_2.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.message_settings 2 | ALTER COLUMN max_message_age SET DEFAULT 30; 3 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /src/main/resources/locale.properties 3 | translation: /src/main/resources/locale_%locale_with_underscore%.properties 4 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_30.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.subscriptions 2 | ADD COLUMN IF NOT EXISTS purchase_type TEXT DEFAULT '' NOT NULL; 3 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_31.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.subscriptions 2 | ADD COLUMN IF NOT EXISTS persistent BOOLEAN DEFAULT FALSE NOT NULL; 3 | 4 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_32.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.subscription_error 2 | ADD COLUMN IF NOT EXISTS notified BOOLEAN DEFAULT FALSE NOT NULL; 3 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_14.sql: -------------------------------------------------------------------------------- 1 | drop index IF EXISTS repbot_schema.voice_activity_relation_key_uindex; 2 | 3 | create index IF NOT EXISTS voice_activity_relation_key_index 4 | on repbot_schema.voice_activity(relation_key); 5 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_33.sql: -------------------------------------------------------------------------------- 1 | drop index IF EXISTS repbot_schema.repuation_log_donated; 2 | 3 | create index IF NOT EXISTS reputation_log_donated 4 | on repbot_schema.reputation_log (guild_id, received, donor_id) WHERE donor_id IS NOT NULL; 5 | 6 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | mkdocs-material = "*" 8 | mkdocs-git-revision-date-localized-plugin = "*" 9 | deepl = "*" 10 | 11 | [dev-packages] 12 | 13 | [requires] 14 | python_version = "3.14" 15 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_36.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE IF EXISTS repbot_schema.guild_settings 2 | DROP COLUMN IF EXISTS emoji_debug; 3 | 4 | ALTER TABLE repbot_schema.abuse_protection 5 | ADD COLUMN IF NOT EXISTS cooldown_direction TEXT DEFAULT 'BIDIRECTIONAL' NOT NULL; 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/web/routes/RoutesBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.web.routes; 7 | 8 | public interface RoutesBuilder { 9 | void buildRoutes(); 10 | } 11 | -------------------------------------------------------------------------------- /tags/remove_reputation.md: -------------------------------------------------------------------------------- 1 | ### How can I remove reputation of a user? 2 | 3 | How you can remove reputation depends on the way the reputation was given to the user. 4 | 5 | **Mention, Answer, Fuzzy, Embed** 6 | Delete the message 7 | 8 | **Added by Reaction** 9 | Delete the reaction of the user 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/ResultType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results; 7 | 8 | public enum ResultType { 9 | NO_MATCH, 10 | MATCH 11 | } 12 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>rainbowdashlabs/rainbowdashlabs" 5 | ], 6 | "baseBranchPatterns": ["main"], 7 | "reviewers": [ 8 | "dlsf", 9 | "RainbowDashLabs", 10 | "Taucher2003", 11 | "yannicklamprecht" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/reactions/util/CheckResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.reactions.util; 7 | 8 | public enum CheckResult { 9 | EMOJI_FOUND, EMOTE_FOUND, NOT_FOUND, UNKNOWN_EMOJI 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheckResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.reactions.util; 7 | 8 | public record EmojiCheckResult(String mention, String id, CheckResult result) { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/ChartProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics; 7 | 8 | public interface ChartProvider { 9 | 10 | byte[] getChart(String title); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/GuildReputationStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots; 7 | 8 | public record GuildReputationStats(int totalReputation, int weekReputation, int todayReputation, long topChannelId) { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/EmbedDisplay.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic; 7 | 8 | import net.dv8tion.jda.api.EmbedBuilder; 9 | 10 | @FunctionalInterface 11 | public interface EmbedDisplay { 12 | void appendTo(EmbedBuilder embedBuilder); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/components/UserHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.components; 7 | 8 | import net.dv8tion.jda.api.entities.User; 9 | 10 | public interface UserHolder { 11 | User user(); 12 | 13 | default long userId() { 14 | return user().getIdLong(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_28.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE VIEW repbot_schema.truncated_reputation_offset AS 2 | SELECT l.guild_id, l.user_id, sum(l.amount)::BIGINT as amount 3 | FROM repbot_schema.reputation_offset l 4 | LEFT JOIN repbot_schema.guild_settings s ON l.guild_id = s.guild_id 5 | WHERE s.reset_date IS NULL 6 | OR l.added > s.reset_date 7 | OR s.reset_date > NOW()::DATE 8 | GROUP BY l.guild_id, user_id; 9 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/components/GuildHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.components; 7 | 8 | import net.dv8tion.jda.api.entities.Guild; 9 | 10 | public interface GuildHolder { 11 | Guild guild(); 12 | 13 | default long guildId(){ 14 | return guild().getIdLong(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/ReplacementProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | 10 | import java.util.List; 11 | 12 | @FunctionalInterface 13 | public interface ReplacementProvider { 14 | List replacements(); 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v5 12 | - uses: actions/setup-python@v6 13 | with: 14 | python-version: 3.14 15 | - run: echo "repbot.docs.chojo.dev" > ./docs/CNAME 16 | - run: pip install pipenv && pipenv install && pipenv run mkdocs gh-deploy --force 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/SubmitResultEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots; 7 | 8 | import de.chojo.repbot.service.reputation.SubmitResult; 9 | 10 | import java.time.Instant; 11 | 12 | public record SubmitResultEntry(SubmitResult submitResult, long channelId, long messageId, Instant instant) { 13 | } 14 | -------------------------------------------------------------------------------- /tags/roles.md: -------------------------------------------------------------------------------- 1 | ### What roles will be managed by the bot? 2 | 3 | The bot will manage all roles which are registered as reputation roles. 4 | The bot will always check the user roles when a user receives reputation. If you add a new role, the bot will adjust the 5 | user roles, when these users receive reputation again. 6 | 7 | When the bot updates user roles it will first remove all roles registered as reputation roles from the user. 8 | It will then add the new reputation role to the user. 9 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/ChannelBlacklist.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class ChannelBlacklist { 11 | private SKUEntry allow = new SKUEntry(); 12 | 13 | public SKUEntry allow() { 14 | return allow; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/LogChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class LogChannel { 11 | private SKUEntry logChannel = new SKUEntry(); 12 | 13 | public SKUEntry logChannel() { 14 | return logChannel; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tags/analyzer_log.md: -------------------------------------------------------------------------------- 1 | ### Why did user XY not receive any reputation or why was the message ignored? 2 | 3 | This can have a lot of reasons and since it is nearly impossible for us to cover all the reasons here, we added 4 | a command which can tell exactly this. The `analyzer log ` command will show you in detail how the 5 | bot processed a message. 6 | 7 | This command is basically showing what the debug emojis are showing as well, but will actually explain why 8 | something happened or not happened. 9 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/Autopost.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class Autopost { 11 | private SKUEntry autopostChannel = new SKUEntry(); 12 | 13 | public SKUEntry autopostChannel() { 14 | return autopostChannel; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_17.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE repbot_schema.guild_settings 2 | DROP COLUMN IF EXISTS manager_role; 3 | 4 | ALTER TABLE repbot_schema.guild_settings 5 | DROP COLUMN IF EXISTS prefix; 6 | 7 | UPDATE repbot_schema.thank_settings 8 | SET reaction = '🏅' 9 | WHERE reaction IS NULL; 10 | 11 | ALTER TABLE repbot_schema.thank_settings 12 | ALTER COLUMN reaction SET NOT NULL; 13 | 14 | ALTER TABLE repbot_schema.thank_settings 15 | ALTER COLUMN reaction SET DEFAULT '🏅'; 16 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/DetailedProfile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class DetailedProfile { 11 | private SKUEntry detailedProfile = new SKUEntry(); 12 | 13 | public SKUEntry detailedProfile() { 14 | return detailedProfile; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/listener/voting/VoteComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.listener.voting; 7 | 8 | import net.dv8tion.jda.api.components.ActionComponent; 9 | import net.dv8tion.jda.api.components.actionrow.ActionRowChildComponent; 10 | import net.dv8tion.jda.api.entities.Member; 11 | 12 | 13 | public record VoteComponent(Member member, ActionRowChildComponent component) { 14 | } 15 | -------------------------------------------------------------------------------- /tags/emojis.md: -------------------------------------------------------------------------------- 1 | ### What are those emojis and what do they mean? 2 | 3 | Those emojis indicate what the bot does with a message: 4 | 5 | - 👀 ➜ Found a thankword 6 | - 💤 ➜ Receiver was on cooldown 7 | - 🔍 ➜ No receiver was found 8 | - ❓ ➜ Receiver has no recent messages in this channel and is missing in the context 9 | - ❔ ➜ Donor is not present in channel 10 | - 🕛 ➜ The referenced message is too old 11 | - 🗨️ ➜ User was prompted for reputation. 12 | 13 | A bot admin can disable these emojis in the `repsettings`. 14 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/AdditionalEmojis.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class AdditionalEmojis { 11 | private SKUEntry additionalEmojis = new SKUEntry(); 12 | 13 | public SKUEntry additionalEmojis() { 14 | return additionalEmojis; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/AdvancedRankings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class AdvancedRankings { 11 | private SKUEntry advancedRankings = new SKUEntry(); 12 | 13 | public SKUEntry advancedRankings() { 14 | return advancedRankings; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/Nickname.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.SKU; 9 | import de.chojo.repbot.config.elements.sku.SKUEntry; 10 | 11 | public class Nickname { 12 | private SKUEntry allow = new SKUEntry(); 13 | 14 | public SKUEntry allow() { 15 | return allow; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/CooldownDirection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.settings.sub; 7 | 8 | public enum CooldownDirection { 9 | UNIDIRECTIONAL, 10 | BIDIRECTIONAL; 11 | 12 | public String localCode() { 13 | return "$%s$".formatted(getClass().getSimpleName().toLowerCase() + "." + this.name().toLowerCase()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/subscriptions/SkuTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.subscriptions; 7 | 8 | import net.dv8tion.jda.api.entities.Entitlement; 9 | 10 | public enum SkuTarget { 11 | GUILD, USER; 12 | 13 | public static SkuTarget fromEntitlement(Entitlement entitlement) { 14 | return entitlement.getGuildId() == null ? USER : GUILD; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_12.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS repbot_schema.self_cleanup 2 | ( 3 | guild_id BIGINT NOT NULL 4 | CONSTRAINT self_cleanup_pk 5 | PRIMARY KEY, 6 | prompted TIMESTAMP DEFAULT NOW() NOT NULL 7 | ); 8 | 9 | 10 | CREATE TABLE IF NOT EXISTS repbot_schema.migrations 11 | ( 12 | guild_id BIGINT 13 | CONSTRAINT migrations_pk 14 | PRIMARY KEY, 15 | prompted TIMESTAMP DEFAULT NOW() NOT NULL, 16 | migrated TIMESTAMP 17 | ); 18 | -------------------------------------------------------------------------------- /src/test/java/de/chojo/repbot/commands/ThankwordsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands; 7 | 8 | import de.chojo.repbot.commands.thankwords.Thankwords; 9 | import org.junit.jupiter.api.Assertions; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class ThankwordsTest { 13 | 14 | @Test 15 | void loadContainer() { 16 | Assertions.assertDoesNotThrow(Thankwords::loadContainer); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/LocaleOverrides.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class LocaleOverrides { 11 | private SKUEntry reputationNameOverride = new SKUEntry(); 12 | 13 | public SKUEntry reputationNameOverride() { 14 | return reputationNameOverride; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tags/prune.md: -------------------------------------------------------------------------------- 1 | ### A user has left the server but still shows up in top command 2 | 3 | The reputation of a user will be removed 14 days after the user has left the server. 4 | 5 | The bot does not check if a user is still on the server when the toplist is retrieved. That is the reason why those 6 | users are still in the top list. 7 | 8 | You can remove all reputation of a single user with the `prune user ` command. 9 | Alternatively you can remove reputation of all users which are no longer on this guild with the `prune guild` command. 10 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/Roles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import net.dv8tion.jda.api.entities.Role; 9 | 10 | public final class Roles { 11 | private Roles() { 12 | throw new UnsupportedOperationException("This is a utility class."); 13 | } 14 | 15 | public static String prettyName(Role role) { 16 | return String.format("%s (%s)", role.getName(), role.getIdLong()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/Guilds.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import net.dv8tion.jda.api.entities.Guild; 9 | 10 | public final class Guilds { 11 | private Guilds() { 12 | throw new UnsupportedOperationException("This is a utility class."); 13 | } 14 | 15 | public static String prettyName(Guild guild) { 16 | return String.format("%s (%s)", guild.getName(), guild.getIdLong()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/Cleanup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access; 7 | 8 | import de.chojo.sadu.queries.api.query.Query; 9 | 10 | import java.util.List; 11 | 12 | public class Cleanup { 13 | public List getCleanupList() { 14 | return Query.query("SELECT guild_id FROM self_cleanup;") 15 | .single() 16 | .mapAs(Long.class) 17 | .all(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/ranking/RankingType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.reputation.sub.ranking; 7 | 8 | public enum RankingType { 9 | RECEIVED, 10 | GIVEN; 11 | 12 | private final String localeKey; 13 | 14 | RankingType() { 15 | localeKey = "ranking." + name().toLowerCase(); 16 | } 17 | 18 | public String localeKey() { 19 | return localeKey; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_3.sql: -------------------------------------------------------------------------------- 1 | -- add the missing unique constrain on table. requires deduplication. 2 | CREATE TEMP TABLE temp_channel ON COMMIT DROP AS 3 | (SELECT DISTINCT guild_id, channel_id 4 | FROM repbot_schema.active_channel); 5 | 6 | DELETE 7 | FROM repbot_schema.active_channel; 8 | 9 | CREATE UNIQUE INDEX IF NOT EXISTS active_channel_guild_id_channel_id_uindex 10 | ON repbot_schema.active_channel (guild_id, channel_id); 11 | 12 | INSERT INTO repbot_schema.active_channel(guild_id, channel_id) 13 | SELECT guild_id, channel_id 14 | FROM temp_channel; 15 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/ranking/RankingScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.reputation.sub.ranking; 7 | 8 | import de.chojo.repbot.dao.access.guild.settings.sub.ReputationMode; 9 | 10 | public enum RankingScope { 11 | GUILD, USER; 12 | 13 | public String localeKey(ReputationMode mode) { 14 | return "ranking.%s.%s".formatted(name().toLowerCase(), mode.name().toLowerCase().replace("_", "")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/web/error/ApiException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.web.error; 7 | 8 | 9 | import io.javalin.http.HttpStatus; 10 | 11 | public class ApiException extends RuntimeException { 12 | private final HttpStatus status; 13 | 14 | public ApiException(HttpStatus status, String message) { 15 | super(message); 16 | this.status = status; 17 | } 18 | 19 | public HttpStatus status() { 20 | return status; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_25.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE repbot_schema.reputation_results 2 | ( 3 | guild_id BIGINT NOT NULL, 4 | channel_id BIGINT NOT NULL, 5 | message_id BIGINT NOT NULL, 6 | result jsonb NOT NULL, 7 | submitted TIMESTAMP DEFAULT (NOW() AT TIME ZONE 'utc') NOT NULL 8 | ); 9 | 10 | CREATE INDEX reputation_results_guild_id_message_id_index 11 | ON repbot_schema.reputation_results (guild_id, message_id); 12 | -------------------------------------------------------------------------------- /tags/request_data.md: -------------------------------------------------------------------------------- 1 | ### How can I request my data? 2 | 3 | You have to be on a server with the Reputation Bot. If you don't have one, join the support server. Make also sure 4 | that your privacy settings are not blocking dms. 5 | 6 | You can request a copy of your data with the `gdpr request` command. 7 | 8 | You will receive a copy of all data as a json file. This file will contain all entries which are related with your user 9 | id. User ids of other users are removed and will not be included in your data. 10 | 11 | You will receive the data within a few hours. 12 | You can request your data every 30 days. 13 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/pagination/GuildList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.pagination; 7 | 8 | import de.chojo.repbot.dao.access.guild.RepGuild; 9 | 10 | import java.util.List; 11 | import java.util.function.Function; 12 | import java.util.function.Supplier; 13 | 14 | public class GuildList extends PageAccess { 15 | public GuildList(Supplier pagecount, Function> pageSupplier) { 16 | super(pagecount, pageSupplier); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/AnalyzerLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class AnalyzerLog { 11 | private SKUEntry longerLogTime = new SKUEntry(); 12 | private int extendedLogHours = 96; 13 | 14 | public SKUEntry longerLogTime() { 15 | return longerLogTime; 16 | } 17 | 18 | public int extendedLogHours() { 19 | return extendedLogHours; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/setup/handler/NewStart.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.setup.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 11 | 12 | public class NewStart implements SlashHandler { 13 | @Override 14 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/ReputationChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class ReputationChannel { 11 | private SKUEntry moreChannel = new SKUEntry(); 12 | private int defaultChannel = 2; 13 | 14 | public SKUEntry moreChannel() { 15 | return moreChannel; 16 | } 17 | 18 | public int defaultChannel() { 19 | return defaultChannel; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: RainbowDashLabs 4 | patreon: eldoriaplugins 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: eldoriaplugins 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/ReputationCategories.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | public class ReputationCategories { 11 | private SKUEntry moreCategories = new SKUEntry(); 12 | private int defaultCategories = 2; 13 | 14 | public SKUEntry moreCategories() { 15 | return moreCategories; 16 | } 17 | 18 | public int defaultCategories() { 19 | return defaultCategories; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/RepGuildId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild; 7 | 8 | import de.chojo.repbot.config.Configuration; 9 | 10 | import javax.sql.DataSource; 11 | 12 | public class RepGuildId extends RepGuild { 13 | private final long guildId; 14 | 15 | public RepGuildId(long guildId, Configuration configuration) { 16 | super(null, configuration); 17 | this.guildId = guildId; 18 | } 19 | 20 | @Override 21 | public long guildId() { 22 | return guildId; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | app: 5 | image: ghcr.io/rainbowdashlabs/reputation-bot:latest 6 | networks: 7 | - repbot 8 | depends_on: 9 | - database 10 | volumes: 11 | - ./config/:/app/config/ 12 | database: 13 | networks: 14 | - repbot 15 | image: postgres:18.1 16 | expose: 17 | - 5432 18 | volumes: 19 | - db_data:/var/lib/postgresql/data 20 | environment: 21 | POSTGRES_USER: "root" 22 | POSTGRES_PASSWORD: "changeme" 23 | POSTGRES_DB: "repbot" 24 | 25 | networks: 26 | repbot: 27 | name: repbot 28 | external: false 29 | 30 | volumes: 31 | db_data: 32 | -------------------------------------------------------------------------------- /docs/invite.md: -------------------------------------------------------------------------------- 1 | # Get the bot 2 | 3 | You have two options when you want the bot. 4 | 5 | ## Public instance 6 | 7 | You can use our public instance which is managed and updated by us. We care about backups and keep your data secure 8 | and save. 9 | 10 | [Click here to invite the bot on your server](https://discord.com/api/oauth2/authorize?client_id=871322553698906142&permissions=1342532672&scope=bot%20applications.commands) 11 | 12 | ## Self-hosting 13 | 14 | Self-host the bot by yourself. In the end we are open source and everyone can use this bot. 15 | 16 | If you want to learn more about the ways to set up and configure the bot take a look at our [hosting page](./hosting.md) 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/pagination/ReputationLogAccess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.pagination; 7 | 8 | import de.chojo.repbot.dao.snapshots.ReputationLogEntry; 9 | 10 | import java.util.List; 11 | import java.util.function.Function; 12 | import java.util.function.Supplier; 13 | 14 | public class ReputationLogAccess extends PageAccess { 15 | public ReputationLogAccess(Supplier pagecount, Function> pageSupplier) { 16 | super(pagecount, pageSupplier); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/Thankswords.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { 3 | "English": [ 4 | "thx", 5 | "thank[sx]?", 6 | "ty", 7 | "tyvm", 8 | "tysm" 9 | ], 10 | "Deutsch": [ 11 | "dan[kg]e?", 12 | "dankeschön" 13 | ], 14 | "Español": [ 15 | "agradezco", 16 | "agradecid[oa]s?", 17 | "gracias" 18 | ], 19 | "Français": [ 20 | "(?:re)?merci" 21 | ], 22 | "Português": [ 23 | "obrigad[oa]s?", 24 | "obrigadíssim[oa]", 25 | "agradecid[oa]", 26 | "grat[oa]" 27 | ], 28 | "Русский": [ 29 | "спс", 30 | "спасиб[ао]?", 31 | "благодарю" 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/Api.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "MismatchedReadAndWriteOfArray"}) 9 | public class Api { 10 | private String host = "0.0.0.0"; 11 | private int port = 8888; 12 | private String url = "https://repbot.chojo.de"; 13 | 14 | public String host() { 15 | return host; 16 | } 17 | 18 | public int port() { 19 | return port; 20 | } 21 | 22 | public String url() { 23 | return url; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/invite/Invite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.invite; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 10 | import de.chojo.repbot.commands.invite.handler.Show; 11 | import de.chojo.repbot.config.Configuration; 12 | 13 | public class Invite extends SlashCommand { 14 | public Invite(Configuration configuration) { 15 | super(Slash.of("invite", "command.invite.description") 16 | .command(new Show(configuration))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/analyzer/ResultSnapshot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.analyzer; 7 | 8 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 9 | import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; 10 | import de.chojo.repbot.dao.snapshots.ResultEntry; 11 | import net.dv8tion.jda.api.entities.Guild; 12 | 13 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 14 | public interface ResultSnapshot { 15 | void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/QueryLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import java.io.IOException; 9 | 10 | public class QueryLoader { 11 | public static String loadQuery(String... names) { 12 | String path = "queries/" + String.join("/", names) + ".sql"; 13 | try { 14 | return new String(QueryLoader.class.getClassLoader().getResourceAsStream(path).readAllBytes()); 15 | } catch (IOException | NullPointerException e) { 16 | throw new RuntimeException("Could not load query: " + path, e); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/ChannelStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots; 7 | 8 | import de.chojo.jdautil.util.MentionUtil; 9 | import de.chojo.sadu.mapper.wrapper.Row; 10 | 11 | import java.sql.SQLException; 12 | 13 | public record ChannelStats(long channelId, long count) { 14 | public static ChannelStats build(Row row) throws SQLException { 15 | return new ChannelStats(row.getLong("channel_id"), row.getLong("count")); 16 | } 17 | 18 | public String fancyString() { 19 | return "%s ➜ %d".formatted(MentionUtil.channel(channelId()), count()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandStatistic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics; 7 | 8 | 9 | import de.chojo.sadu.mapper.wrapper.Row; 10 | 11 | import java.sql.SQLException; 12 | import java.time.LocalDate; 13 | 14 | public record CommandStatistic(LocalDate date, String command, int count) { 15 | 16 | public static CommandStatistic build(Row rs, String dateKey) throws SQLException { 17 | return new CommandStatistic(rs.getDate(dateKey).toLocalDate(), 18 | rs.getString("command"), 19 | rs.getInt("count")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/autopost/RefreshType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.settings.sub.autopost; 7 | 8 | public enum RefreshType { 9 | /** 10 | * Delete old posts and send again. 11 | */ 12 | DELETE_AND_REPOST, 13 | /** 14 | * Send again. 15 | */ 16 | REPOST, 17 | /** 18 | * Update the original message. 19 | */ 20 | UPDATE; 21 | 22 | @Override 23 | public String toString() { 24 | return "%s.%s.name".formatted(getClass().getSimpleName().toLowerCase(), name().toLowerCase().replace("_", "")); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tags/delete_data.md: -------------------------------------------------------------------------------- 1 | ### How can I request deletion of my data? 2 | 3 | You have to be on a server with the Reputation Bot. If you don't have one, join the support server. 4 | 5 | You can request deletion of your data with the `gdpr delete` command. 6 | 7 | Once you have submitted your request your data will be deleted within a few hours. You will not receive a confirmation 8 | of the deletion. You can not abort the deletion of your data. 9 | You may request your data again after some time, if you want to check that your data was deleted. 10 | 11 | We will delete all your received reputation on all servers. 12 | We will remove your user id on every given reputation by you, but we will not delete these reputations, since they don't 13 | belong to you. 14 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gradle:jdk21-alpine as build 2 | 3 | ARG GITHUB_ACTIONS=false 4 | ARG GITHUB_REF_TYPE=null 5 | ARG GITHUB_REF_NAME=null 6 | ARG GITHUB_SHA=null 7 | ARG GITHUB_ACTIONS=$GITHUB_ACTIONS 8 | ARG GITHUB_REF_TYPE=$GITHUB_REF_TYPE 9 | ARG GITHUB_REF_NAME=$GITHUB_REF_NAME 10 | ARG GITHUB_SHA=$GITHUB_SHA 11 | 12 | COPY . . 13 | RUN gradle clean shadowJar --no-daemon -x test -x javadocJar -x sourcesJar 14 | 15 | FROM eclipse-temurin:25-alpine as runtime 16 | ENV DOCKER=true 17 | 18 | WORKDIR /app 19 | 20 | COPY --from=build /home/gradle/build/libs/rep-bot-*-all.jar bot.jar 21 | 22 | ENTRYPOINT ["java", "-Dbot.config=config/config.json", "-Dlog4j2.configurationFile=config/log4j2.xml", "-Dcjda.localisation.error.name=false", "-jar" , "bot.jar"] 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | **/build/ 3 | !src/**/build/ 4 | .idea/ 5 | 6 | # Ignore Gradle GUI config 7 | gradle-app.setting 8 | 9 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 10 | !gradle-wrapper.jar 11 | 12 | # Cache of project 13 | .gradletasknamecache 14 | 15 | # CMake 16 | cmake-build-*/ 17 | 18 | # Maven 19 | target/ 20 | pom.xml.tag 21 | pom.xml.releaseBackup 22 | pom.xml.versionsBackup 23 | pom.xml.next 24 | release.properties 25 | dependency-reduced-pom.xml 26 | buildNumber.properties 27 | .mvn/timing.properties 28 | .mvn/wrapper/maven-wrapper.jar 29 | 30 | # Hewo Mac users. this is for you <3 31 | .DS_Store 32 | 33 | # Bot internal generated data 34 | /config/ 35 | /logs/ 36 | /out/ 37 | 38 | /site/ 39 | /.direnv 40 | .run 41 | .env 42 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/dashboard/Dashboard.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.dashboard; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 10 | import de.chojo.repbot.commands.dashboard.handler.Show; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | 13 | public class Dashboard extends SlashCommand { 14 | public Dashboard(GuildRepository guildRepository) { 15 | super(Slash.of("dashboard", "command.dashboard.description") 16 | .guildOnly() 17 | .command(new Show(guildRepository))); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/RoleAccessException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service; 7 | 8 | import net.dv8tion.jda.api.entities.Role; 9 | 10 | public class RoleAccessException extends RuntimeException { 11 | private final Role role; 12 | 13 | /** 14 | * Constructs a new exception with {@code null} as its detail message. 15 | * The cause is not initialized, and may subsequently be initialized by a 16 | * call to {@link #initCause}. 17 | */ 18 | public RoleAccessException(Role role) { 19 | this.role = role; 20 | } 21 | 22 | public Role role() { 23 | return role; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/match/ThankType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results.match; 7 | 8 | public enum ThankType { 9 | FUZZY("thankType.fuzzy.name"), 10 | MENTION("thankType.mention.name"), 11 | ANSWER("thankType.answer.name"), 12 | DIRECT("thankType.direct.name"), 13 | REACTION("thankType.reaction.name"), 14 | EMBED("thankType.embed.name"); 15 | 16 | private final String nameLocaleKey; 17 | 18 | ThankType(String nameLocaleKey) { 19 | this.nameLocaleKey = nameLocaleKey; 20 | } 21 | 22 | public String nameLocaleKey() { 23 | return nameLocaleKey; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/feature/ReputationLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku.feature; 7 | 8 | import de.chojo.repbot.config.elements.sku.SKUEntry; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 14 | public class ReputationLog { 15 | 16 | private SKUEntry extendedPages = new SKUEntry(); 17 | private int defaultSize = 2; 18 | 19 | public SKUEntry extendedPages() { 20 | return extendedPages; 21 | } 22 | 23 | public int defaultSize() { 24 | return defaultSize; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/debug/Debug.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.debug; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 10 | import de.chojo.repbot.commands.debug.handler.Show; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | 13 | public class Debug extends SlashCommand { 14 | 15 | public Debug(GuildRepository guildRepository) { 16 | super(Slash.of("debug", "command.debug.description") 17 | .guildOnly() 18 | .adminCommand() 19 | .command(new Show(guildRepository))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/jackson/BotModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.jackson; 7 | 8 | import com.fasterxml.jackson.core.Version; 9 | import com.fasterxml.jackson.databind.module.SimpleModule; 10 | import de.chojo.repbot.config.elements.sku.SKUEntry; 11 | import de.chojo.repbot.config.jackson.deserializer.SKUEntryDeserializer; 12 | import de.chojo.repbot.config.jackson.serializer.SKUEntrySerializer; 13 | 14 | public class BotModule extends SimpleModule { 15 | public BotModule() { 16 | super("RepBotModule", Version.unknownVersion()); 17 | addSerializer(SKUEntry.class, new SKUEntrySerializer()); 18 | addDeserializer(SKUEntry.class, new SKUEntryDeserializer()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tags/no_reputation.md: -------------------------------------------------------------------------------- 1 | # Why can't I give reputation to user XY? 2 | 3 | This can have several reasons: 4 | - The user is not in the context for this message 5 | - You gave reputation to this user recently 6 | - This user gave reputation to you recently 7 | 8 | Use `Apps > Message Log` to see why no reputation was given. 9 | 10 | To thank a user make sure that: 11 | - The user has written at least one message after a message of you 12 | - The message of the user you want to thank is not too old (How old depends on the server settings) 13 | - You haven't received reputation from this user shortly 14 | 15 | You can also give reputation to users you currently share or recently shared a voice channel with. 16 | You can read more about this mechanic on our [abuse protection page]() 17 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/SKUEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku; 7 | 8 | import de.chojo.jdautil.interactions.base.SkuMeta; 9 | import de.chojo.jdautil.interactions.premium.SKU; 10 | import de.chojo.repbot.dao.access.guild.subscriptions.Subscription; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.List; 15 | 16 | public class SKUEntry implements SkuMeta { 17 | private List skus = new ArrayList<>(); 18 | 19 | public SKUEntry() { 20 | } 21 | 22 | public SKUEntry(List skus) { 23 | this.skus = skus; 24 | } 25 | 26 | @Override 27 | public Collection sku() { 28 | return skus; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/AnalyzerSettings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 9 | public class AnalyzerSettings { 10 | private int historySize = 100; 11 | private int voiceMembers = 10; 12 | private int latestMaxHours = 12; 13 | private float minFuzzyScore = 0.9f; 14 | 15 | public int latestMaxHours() { 16 | return latestMaxHours; 17 | } 18 | 19 | public float minFuzzyScore() { 20 | return minFuzzyScore; 21 | } 22 | 23 | public int historySize() { 24 | return Math.min(historySize, 100); 25 | } 26 | 27 | public int voiceMembers() { 28 | return voiceMembers; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/components/MemberHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.components; 7 | 8 | import net.dv8tion.jda.api.entities.Guild; 9 | import net.dv8tion.jda.api.entities.Member; 10 | import net.dv8tion.jda.api.entities.User; 11 | 12 | public interface MemberHolder extends UserHolder, GuildHolder { 13 | Member member(); 14 | 15 | default long memberId() { 16 | return member().getIdLong(); 17 | } 18 | 19 | @Override 20 | default User user() { 21 | return member().getUser(); 22 | } 23 | 24 | @Override 25 | default Guild guild() { 26 | return member().getGuild(); 27 | } 28 | 29 | @Override 30 | default long guildId(){ 31 | return guild().getIdLong(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/OnboardingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service; 7 | 8 | import de.chojo.jdautil.wrapper.EventContext; 9 | import de.chojo.repbot.dao.provider.GuildRepository; 10 | import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | import net.dv8tion.jda.api.hooks.ListenerAdapter; 13 | 14 | public class OnboardingService extends ListenerAdapter { 15 | private final GuildRepository repository; 16 | 17 | public OnboardingService(GuildRepository repository) { 18 | this.repository = repository; 19 | } 20 | 21 | public void start(SlashCommandInteractionEvent event, EventContext context) { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/krile.yaml: -------------------------------------------------------------------------------- 1 | # The pretty name of the repository. Otherwise, the identifier is used. 2 | name: "Reputation Bot" 3 | # The repository description to describe what the tags contain 4 | description: "Tags for the reputation bot" 5 | # A list of categories, which describe this repository 6 | category: ["reputation bot", "discord bot", "bot", "discord"] 7 | # Mark this repository as public. 8 | # This will make it appear in the search. 9 | # People can still import your repository via the identifier or url. 10 | # To appear in the search you also need to define a name, description and set a language 11 | public: true 12 | # Set the language of the repo 13 | language: en 14 | # Change the directory where the tags are located 15 | # Default is root 16 | # This allows you to include your tags in your project instead of an extra repository. 17 | # Our tags are contained in a directory called "tags" 18 | directory: tags 19 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Checklist** 2 | - [ ] I made changes to commands 3 | - [ ] I fully localised the command 4 | - [ ] I fully checked the commands functionality 5 | 6 | - [ ] I added new localisation codes 7 | - [ ] I fully translated it for all languages 8 | - [ ] I sorted properties alphabetically 9 | 10 | 11 | - [ ] I made changes to the database 12 | - [ ] I added my changed to a patch file 13 | - [ ] I made sure my database was up to date 14 | - [ ] I checked that the migration works 15 | 16 | - [ ] I made changes to internal structure 17 | 18 | 19 | **Short Description** 20 | 21 | 22 | **Detailed Description** 23 | 24 | 25 | 26 | 27 | Closes # 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/entitlement/Delete.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.entitlement; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 11 | import net.dv8tion.jda.api.interactions.commands.OptionMapping; 12 | 13 | public class Delete implements SlashHandler { 14 | @Override 15 | public void onSlashCommand(SlashCommandInteractionEvent slash, EventContext eventContext) { 16 | slash.getJDA().deleteTestEntitlement(slash.getOption("entitlementid", OptionMapping::getAsLong)).complete(); 17 | slash.reply("Deleted entitlement").complete(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Checklist** 2 | - [ ] I made changes to commands 3 | - [ ] I fully localised the command 4 | - [ ] I fully checked the commands functionality 5 | 6 | - [ ] I added new localisation codes 7 | - [ ] I fully translated it for all languages 8 | - [ ] I sorted properties alphabetically 9 | 10 | 11 | - [ ] I made changes to the database 12 | - [ ] I added my changed to a patch file 13 | - [ ] I made sure my database was up to date 14 | - [ ] I checked that the migration works 15 | 16 | - [ ] I made changes to internal structure 17 | 18 | 19 | **Short Description** 20 | 21 | 22 | **Detailed Description** 23 | 24 | 25 | 26 | 27 | Closes # 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/element/ShardStatistic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic.element; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.repbot.statistic.ReplacementProvider; 10 | import net.dv8tion.jda.api.JDA; 11 | 12 | import java.util.List; 13 | 14 | public record ShardStatistic(int shard, JDA.Status status, long analyzedMessages, 15 | long guilds) implements ReplacementProvider { 16 | 17 | @Override 18 | public List replacements() { 19 | return List.of(Replacement.create("analyzed_messages_shard", analyzedMessages), Replacement.create("shard_status", status.name()), 20 | Replacement.create("shard_id", shard), Replacement.create("shard_guilds", guilds)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/MagicImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | 9 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 10 | public class MagicImage { 11 | private String magicImageLink = ""; 12 | private int magicImagineChance = 10; 13 | private int magicImageCooldown = 30; 14 | private int magicImageDeleteSchedule = 60; 15 | 16 | public String magicImageLink() { 17 | return magicImageLink; 18 | } 19 | 20 | public int magicImagineChance() { 21 | return magicImagineChance; 22 | } 23 | 24 | public int magicImageCooldown() { 25 | return magicImageCooldown; 26 | } 27 | 28 | public int magicImageDeleteSchedule() { 29 | return magicImageDeleteSchedule; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/reputation/SubmitResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service.reputation; 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator; 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | import de.chojo.jdautil.localization.util.Replacement; 11 | 12 | import java.util.List; 13 | 14 | public record SubmitResult(SubmitResultType type, List replacements) { 15 | 16 | public static SubmitResult of(SubmitResultType type, Replacement... replacements) { 17 | return of(type, List.of(replacements)); 18 | } 19 | 20 | @JsonCreator 21 | public static SubmitResult of(@JsonProperty("type") SubmitResultType type, @JsonProperty("replacements") List replacements) { 22 | return new SubmitResult(type, replacements); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/UserStatistic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics; 7 | 8 | import de.chojo.sadu.mapper.wrapper.Row; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.sql.SQLException; 12 | import java.time.LocalDate; 13 | 14 | public record UserStatistic(LocalDate date, int donors, int receivers, int total) implements Comparable { 15 | public static UserStatistic build(Row rs, String dateKey) throws SQLException { 16 | return new UserStatistic(rs.getDate(dateKey).toLocalDate(), 17 | rs.getInt("donor_count"), rs.getInt("receiver_count"), rs.getInt("total_count")); 18 | } 19 | 20 | @Override 21 | public int compareTo(@NotNull UserStatistic o) { 22 | return date().compareTo(o.date()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/database/postgresql/1/patch_4.sql: -------------------------------------------------------------------------------- 1 | DROP MATERIALIZED VIEW IF EXISTS repbot_schema.data_statistics; 2 | 3 | CREATE MATERIALIZED VIEW repbot_schema.data_statistics AS( 4 | SELECT (SELECT COUNT(1) FROM repbot_schema.guild_settings) AS guilds, 5 | (SELECT COUNT(1) FROM repbot_schema.active_channel) AS channel, 6 | (SELECT COUNT(1) FROM repbot_schema.reputation_log) AS total_reputation, 7 | (SELECT COUNT(1) 8 | FROM repbot_schema.reputation_log 9 | WHERE received > NOW() - '1 DAY'::INTERVAL) AS today_reputation, 10 | (SELECT COUNT(1) 11 | FROM repbot_schema.reputation_log 12 | WHERE received > NOW() - '1 WEEK'::INTERVAL) AS weekly_reputation, 13 | (SELECT COUNT(1) / 4 14 | FROM repbot_schema.reputation_log 15 | WHERE received > NOW() - '4 WEEK'::INTERVAL) AS weekly_avg_reputation ); 16 | 17 | REFRESH MATERIALIZED VIEW repbot_schema.data_statistics; 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hello and welcome new contributor. 2 | 3 | # Issues 4 | Please make sure to describe your issue as precisely as possible. 5 | 6 | # Pull Requests 7 | When you create a new pull request you have to take care of a few things. 8 | 9 | - Create a feature branch based on the main branch E.g. `feature/my-feature` 10 | - Give your feature branch a reasonable name 11 | - Make your changes 12 | - Make sure your feature branch is rebased on the latest commit on the main branch 13 | - Open a PR 14 | - Set main as a target 15 | - Describe what and why you changed it. 16 | - Submit your PR 17 | - Keep an eye if any changes are requested or if you receive any comments. 18 | - (Apply changes to your PR) 19 | - You PR gets merged or denied. 20 | 21 | Thank you for your contribution! 22 | 23 | **Disclaimer:** Vibe coded PRs will be closes without any comments. We won't spend our time on reviewing slop, when you don't want to spend time on properly developing a change. 24 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyResultReason.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results.empty; 7 | 8 | public enum EmptyResultReason { 9 | NO_PATTERN("emptyresultreason.nopattern.description"), 10 | NO_MATCH("emptyresultreason.nomatch.description"), 11 | REFERENCE_MESSAGE_NOT_FOUND("emptyresultreason.referencemessagenotfound.description"), 12 | INSUFFICIENT_SCORE("emptyresultreason.insufficientscore.description"), 13 | INTERNAL_ERROR("emptyresultreason.internalerror.description"), 14 | TARGET_NOT_ON_GUILD("emptyresultreason.targetnotonguild.description"); 15 | 16 | private final String localeKey; 17 | 18 | EmptyResultReason(String localeKey) { 19 | this.localeKey = localeKey; 20 | } 21 | 22 | public String localeKey() { 23 | return localeKey; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/messages/Messages.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.messages; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.SubCommand; 10 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 11 | import de.chojo.repbot.commands.messages.handler.States; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | 14 | public class Messages extends SlashCommand { 15 | public Messages(GuildRepository guildRepository) { 16 | super(Slash.of("messages", "command.messages.description") 17 | .guildOnly() 18 | .adminCommand() 19 | .subCommand(SubCommand.of("states", "command.messages.states.description") 20 | .handler(new States(guildRepository))) 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/BaseSettings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal", "MismatchedQueryAndUpdateOfCollection"}) 12 | public class BaseSettings { 13 | private String token = ""; 14 | private List botOwner = new ArrayList<>(); 15 | private long botGuild = 0L; 16 | private long privateSupportChannel = 0L; 17 | 18 | public String token() { 19 | return token; 20 | } 21 | 22 | public boolean isOwner(long id) { 23 | return botOwner.contains(id); 24 | } 25 | 26 | public long botGuild() { 27 | return botGuild; 28 | } 29 | 30 | public long privateSupportChannel() { 31 | return privateSupportChannel; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/jackson/serializer/SKUEntrySerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.jackson.serializer; 7 | 8 | import com.fasterxml.jackson.core.JsonGenerator; 9 | import com.fasterxml.jackson.databind.SerializerProvider; 10 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 11 | import de.chojo.jdautil.interactions.premium.SKU; 12 | import de.chojo.repbot.config.elements.sku.SKUEntry; 13 | 14 | import java.io.IOException; 15 | 16 | public class SKUEntrySerializer extends StdSerializer { 17 | 18 | public SKUEntrySerializer() { 19 | super(SKUEntry.class); 20 | } 21 | 22 | @Override 23 | public void serialize(SKUEntry value, JsonGenerator gen, SerializerProvider provider) throws IOException { 24 | gen.writeObject(value.sku().stream().mapToLong(SKU::skuId).toArray()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/Badges.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | import java.util.Optional; 9 | 10 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "MismatchedReadAndWriteOfArray"}) 11 | public class Badges { 12 | private boolean enables = true; 13 | private String[] badges = new String[0]; 14 | 15 | /** 16 | * Retrieve the badge for the rank. 17 | * 18 | * @param rank rank to get the badge 19 | * @return badge if a badge is present for this rank. 20 | */ 21 | public Optional badge(int rank) { 22 | if (rank == 0) return Optional.empty(); 23 | if (!enables) return Optional.empty(); 24 | if (rank > badges.length) { 25 | return Optional.empty(); 26 | } 27 | return Optional.ofNullable(badges[rank - 1]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/serialization/ThankwordsContainer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.serialization; 7 | 8 | import java.util.Collections; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 15 | public class ThankwordsContainer { 16 | private Map> defaults = new HashMap<>(); 17 | 18 | public List get(String key) { 19 | for (var entry : defaults.entrySet()) { 20 | if (entry.getKey().equalsIgnoreCase(key)) { 21 | return entry.getValue(); 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | public Set getAvailableLanguages() { 28 | return Collections.unmodifiableSet(defaults.keySet()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/AnalyzerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service; 7 | 8 | import de.chojo.repbot.config.Configuration; 9 | import de.chojo.repbot.dao.access.Analyzer; 10 | 11 | import java.util.concurrent.ScheduledExecutorService; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | public class AnalyzerService implements Runnable { 15 | private final Analyzer analyzer; 16 | 17 | private AnalyzerService(Analyzer analyzer) { 18 | this.analyzer = analyzer; 19 | } 20 | 21 | public static void create(ScheduledExecutorService executorService, Analyzer analyzer) { 22 | var analyzerService = new AnalyzerService(analyzer); 23 | executorService.scheduleAtFixedRate(analyzerService, 1, 60, TimeUnit.MINUTES); 24 | } 25 | 26 | @Override 27 | public void run() { 28 | analyzer.cleanup(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docker/dev.docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | pgdatabase: 3 | image: postgres:14.5 4 | environment: 5 | POSTGRES_USER: "root" 6 | POSTGRES_PASSWORD: "changeme" 7 | POSTGRES_DB: "postgres" 8 | networks: 9 | - repbot 10 | volumes: 11 | - database:/var/lib/postgresql/data/ 12 | ports: 13 | - 5432:5432 14 | profiles: 15 | - default 16 | - app 17 | pgdatabase_unpersisted: 18 | image: postgres:14.5 19 | networks: 20 | - repbot 21 | environment: 22 | POSTGRES_USER: "root" 23 | POSTGRES_PASSWORD: "changeme" 24 | POSTGRES_DB: "postgres" 25 | ports: 26 | - 5432:5432 27 | profiles: 28 | - unpersisted 29 | app: 30 | build: 31 | context: .. 32 | dockerfile: docker/Dockerfile 33 | networks: 34 | - repbot 35 | profiles: 36 | - app 37 | volumes: 38 | - ./config/:/app/config/ 39 | 40 | volumes: 41 | database: 42 | 43 | networks: 44 | repbot: 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/sku/Subscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements.sku; 7 | 8 | import de.chojo.jdautil.interactions.base.SkuMeta; 9 | import de.chojo.jdautil.interactions.premium.SKU; 10 | 11 | import java.util.List; 12 | 13 | public class Subscription { 14 | String name = ""; 15 | long subscriptionSku = 0; 16 | long lifetimeSku = 0; 17 | 18 | public String name() { 19 | return name; 20 | } 21 | 22 | public long subscriptionSku() { 23 | return subscriptionSku; 24 | } 25 | 26 | public long lifetimeSku() { 27 | return lifetimeSku; 28 | } 29 | 30 | public SkuMeta lifetimeSkuMeta() { 31 | return () -> List.of(new SKU(lifetimeSku)); 32 | } 33 | 34 | public SkuMeta subscriptionSkuMeta() { 35 | return () -> List.of(new SKU(subscriptionSku)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/DonorRoles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.settings.sub.thanking; 7 | 8 | import de.chojo.repbot.dao.access.guild.settings.sub.Thanking; 9 | import net.dv8tion.jda.api.entities.Guild; 10 | 11 | import java.util.Set; 12 | 13 | public class DonorRoles extends RolesHolder { 14 | private final Thanking thanking; 15 | 16 | public DonorRoles(Thanking thanking, Set roleIds) { 17 | super(thanking, roleIds); 18 | this.thanking = thanking; 19 | } 20 | 21 | @Override 22 | public Guild guild() { 23 | return thanking.guild(); 24 | } 25 | 26 | @Override 27 | public long guildId() { 28 | return thanking.guildId(); 29 | } 30 | 31 | @Override 32 | protected String targetTable() { 33 | return "donor_roles"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/gdpr/Gdpr.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.gdpr; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.SubCommand; 10 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 11 | import de.chojo.repbot.commands.gdpr.handler.Delete; 12 | import de.chojo.repbot.commands.gdpr.handler.Request; 13 | 14 | public class Gdpr extends SlashCommand { 15 | 16 | public Gdpr(de.chojo.repbot.dao.access.Gdpr gdpr) { 17 | super(Slash.of("gdpr", "command.gdpr.description") 18 | .subCommand(SubCommand.of("request", "command.gdpr.request.description") 19 | .handler(new Request(gdpr))) 20 | .subCommand(SubCommand.of("delete", "command.gdpr.delete.description") 21 | .handler(new Delete(gdpr)))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Commands 2 | 3 | The command list is outdated. Use the slash commands in discord to see the available commands. 4 | 5 | User commands are: 6 | 7 | - `rep` - Shows the user reputation or reputation of another user. 8 | - `top` - Shows the top users from this server. 9 | - `info` - Shows various information about the bot. 10 | - `dashboard` - metrics about your server 11 | 12 | Team commands are: 13 | 14 | - `repsettings` - Manage your server settings 15 | - `reactions` - Manage the reactions used to give reputation 16 | - `channel` - Manage reputation channel 17 | - `roles` - Manage reputation and bot roles 18 | - `locale` - Change the bot locale 19 | - `log` - Get the recent donated or received reputation of a user. Or reputation information about a message. 20 | - `scan` - Scan a channel for reputation messages. 21 | - `prune` - Remove all reputations or a user or of users which are no longer on the guild (Removal of leaving users will be handled by us automatically. You won't need this normally) 22 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/top/Top.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.top; 7 | 8 | import de.chojo.jdautil.interactions.slash.Argument; 9 | import de.chojo.jdautil.interactions.slash.Slash; 10 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 11 | import de.chojo.repbot.commands.ranking.handler.guild.GuildReceived; 12 | import de.chojo.repbot.config.Configuration; 13 | import de.chojo.repbot.dao.provider.GuildRepository; 14 | 15 | public class Top extends SlashCommand { 16 | public Top(GuildRepository guildRepository, Configuration configuration) { 17 | super(Slash.of("top", "command.top.description") 18 | .guildOnly() 19 | .command(new GuildReceived(guildRepository, configuration, false)) 20 | .argument(Argument.text("mode", "command.top.options.mode.description").withAutoComplete())); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/ReceiverRoles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.settings.sub.thanking; 7 | 8 | import de.chojo.repbot.dao.access.guild.settings.sub.Thanking; 9 | import net.dv8tion.jda.api.entities.Guild; 10 | 11 | import java.util.Set; 12 | 13 | public class ReceiverRoles extends RolesHolder { 14 | private final Thanking thanking; 15 | 16 | public ReceiverRoles(Thanking thanking, Set roleIds) { 17 | super(thanking, roleIds); 18 | this.thanking = thanking; 19 | } 20 | 21 | @Override 22 | public Guild guild() { 23 | return thanking.guild(); 24 | } 25 | 26 | @Override 27 | public long guildId() { 28 | return thanking.guildId(); 29 | } 30 | 31 | @Override 32 | protected String targetTable() { 33 | return "receiver_roles"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/Parser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.Objects; 11 | 12 | public final class Parser { 13 | private Parser() { 14 | throw new UnsupportedOperationException("This is a utility class."); 15 | } 16 | 17 | @Nullable 18 | public static > T parseEnum(String value, Class enumClass) { 19 | for (T constant : enumClass.getEnumConstants()) { 20 | if (constant.name().equalsIgnoreCase(value)) { 21 | return constant; 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | public static > Enum parseEnum(String value, Class enumClass, Enum defaultValue) { 28 | return Objects.requireNonNullElse(parseEnum(value, enumClass), defaultValue); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics.builder; 7 | 8 | import de.chojo.repbot.dao.snapshots.statistics.CountStatistics; 9 | import de.chojo.repbot.dao.snapshots.statistics.LabeledCountStatistic; 10 | 11 | import java.util.ArrayList; 12 | import java.util.LinkedHashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public class LabeledCountStatisticBuilder { 17 | private final Map> stats = new LinkedHashMap<>(); 18 | 19 | public LabeledCountStatisticBuilder add(String label, CountStatistics statistic) { 20 | stats.computeIfAbsent(label, key -> new ArrayList<>()).add(statistic); 21 | return this; 22 | } 23 | 24 | public LabeledCountStatistic build() { 25 | return new LabeledCountStatistic(stats); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/locale/handler/Reset.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.locale.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Reset implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public Reset(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | guildRepository.guild(event.getGuild()).settings().general().language(null); 23 | event.reply("command.locale.reset.message.changed").complete(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/pagination/Ranking.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.pagination; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.repbot.dao.snapshots.RankingEntry; 10 | 11 | import java.util.List; 12 | import java.util.function.Function; 13 | import java.util.function.Supplier; 14 | 15 | public class Ranking extends PageAccess { 16 | private final String title; 17 | private final Replacement replacement; 18 | 19 | public Ranking(String title, Replacement replacement, Supplier pagecount, Function> pageSupplier) { 20 | super(pagecount, pageSupplier); 21 | this.title = title; 22 | this.replacement = replacement; 23 | } 24 | 25 | public String title() { 26 | return title; 27 | } 28 | 29 | public Replacement replacement() { 30 | return replacement; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/supporter/handler/Refresh.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.supporter.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.service.PremiumService; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Refresh implements SlashHandler { 14 | private final PremiumService premiumService; 15 | 16 | public Refresh(PremiumService premiumService) { 17 | this.premiumService = premiumService; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext eventContext) { 22 | premiumService.refresh(event.getGuild()); 23 | event.reply(eventContext.localize("command.supporter.refresh.message.refreshed")).setEphemeral(true).queue(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/InvalidateCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class InvalidateCache implements SlashHandler { 14 | 15 | private final GuildRepository guildRepository; 16 | 17 | public InvalidateCache(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | guildRepository.invalidate(event.getOption("guild").getAsLong()); 24 | event.reply("Invalidated guild cache").setEphemeral(true).complete(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/subscriptions/SubscriptionError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.subscriptions; 7 | 8 | import de.chojo.repbot.util.SupporterFeature; 9 | import de.chojo.sadu.mapper.wrapper.Row; 10 | import de.chojo.sadu.queries.converter.StandardValueConverter; 11 | 12 | import java.sql.SQLException; 13 | import java.time.Instant; 14 | 15 | public record SubscriptionError(SupporterFeature type, Instant created, Instant lastSend, int count, boolean notified) { 16 | 17 | public static SubscriptionError build(Row row) throws SQLException { 18 | return new SubscriptionError(row.getEnum("type", SupporterFeature.class), 19 | row.get("date_inserted", StandardValueConverter.INSTANT_TIMESTAMP), 20 | row.get("last_send", StandardValueConverter.INSTANT_TIMESTAMP), 21 | row.getInt("count"), 22 | row.getBoolean("notified")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/messages/log/handler/MessageAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.messages.log.handler; 7 | 8 | import de.chojo.jdautil.interactions.message.MessageHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.commands.log.handler.Analyzer; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; 13 | 14 | public class MessageAnalyzer implements MessageHandler { 15 | private final GuildRepository guildRepository; 16 | 17 | public MessageAnalyzer(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onMessage(MessageContextInteractionEvent event, EventContext eventContext) { 23 | Analyzer.sendAnalyzerLog(event, guildRepository, event.getTarget().getIdLong(), eventContext); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics; 7 | 8 | import de.chojo.sadu.mapper.wrapper.Row; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.sql.SQLException; 12 | import java.time.LocalDateTime; 13 | 14 | public record CountStatistics(LocalDateTime date, int count) implements Comparable { 15 | 16 | public static CountStatistics build(Row rs, String dateKey) throws SQLException { 17 | return build(rs, "count", dateKey); 18 | } 19 | 20 | public static CountStatistics build(Row rs, String countKey, String dateKey) throws SQLException { 21 | return new CountStatistics(rs.getTimestamp(dateKey).toLocalDateTime(), 22 | rs.getInt(countKey)); 23 | } 24 | 25 | @Override 26 | public int compareTo(@NotNull CountStatistics o) { 27 | return date().compareTo(o.date()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/Links.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 9 | public class Links { 10 | private String tos = ""; 11 | private String invite = "https://discord.com/oauth2/authorize?client_id=834843896579489794&scope=bot&permissions=1342532672"; 12 | private String support = ""; 13 | private String website = "https://rainbowdashlabs.github.io/reputation-bot/"; 14 | private String faq = "https://rainbowdashlabs.github.io/reputation-bot/faq"; 15 | 16 | public String tos() { 17 | return tos; 18 | } 19 | 20 | public String invite() { 21 | return invite; 22 | } 23 | 24 | public String support() { 25 | return support; 26 | } 27 | 28 | public String website() { 29 | return website; 30 | } 31 | 32 | public String faq() { 33 | return faq; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/Leave.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.util.Guilds; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Leave implements SlashHandler { 14 | @Override 15 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 16 | var guild = event.getJDA().getShardManager().getGuildById(event.getOption("guild_id").getAsLong()); 17 | 18 | if (guild == null) { 19 | event.reply("Guild not present.").setEphemeral(true).complete(); 20 | return; 21 | } 22 | 23 | event.reply("Leaving guild " + Guilds.prettyName(guild)).setEphemeral(true).complete(); 24 | guild.leave().complete(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/element/GlobalShardStatistic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic.element; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.repbot.statistic.ReplacementProvider; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class GlobalShardStatistic implements ReplacementProvider { 15 | private final long analyzedMessages; 16 | 17 | public GlobalShardStatistic(List shardStatistics) { 18 | analyzedMessages = shardStatistics.stream() 19 | .map(ShardStatistic::analyzedMessages).reduce(0L, Long::sum); 20 | } 21 | 22 | public long analyzedMessages() { 23 | return analyzedMessages; 24 | } 25 | 26 | 27 | @Override 28 | public List replacements() { 29 | return Collections.singletonList(Replacement.create("analyzed_messages", analyzedMessages)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/jackson/deserializer/SKUEntryDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.jackson.deserializer; 7 | 8 | import com.fasterxml.jackson.core.JacksonException; 9 | import com.fasterxml.jackson.core.JsonParser; 10 | import com.fasterxml.jackson.databind.DeserializationContext; 11 | import com.fasterxml.jackson.databind.JsonDeserializer; 12 | import de.chojo.jdautil.interactions.premium.SKU; 13 | import de.chojo.repbot.config.elements.sku.SKUEntry; 14 | 15 | import java.io.IOException; 16 | import java.util.Arrays; 17 | import java.util.stream.Collectors; 18 | 19 | public class SKUEntryDeserializer extends JsonDeserializer { 20 | @Override 21 | public SKUEntry deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { 22 | long[] longs = p.readValueAs(long[].class); 23 | return new SKUEntry(Arrays.stream(longs).mapToObj(SKU::new).collect(Collectors.toList())); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/system/Status.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.system; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.statistic.Statistic; 11 | import net.dv8tion.jda.api.EmbedBuilder; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class Status implements SlashHandler { 15 | private final Statistic statistic; 16 | 17 | public Status(Statistic statistic) { 18 | this.statistic = statistic; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | var builder = new EmbedBuilder(); 24 | var systemStatistic = statistic.getSystemStatistic(); 25 | systemStatistic.appendTo(builder); 26 | event.replyEmbeds(builder.build()).complete(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/log/LogDisable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.log; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class LogDisable implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public LogDisable(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | guildRepository.guild(event.getGuild()).settings().logChannel().active(false); 24 | event.reply(context.localize("command.channel.log.disable.message.disabled")).setEphemeral(true).queue(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/locale/handler/List.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.locale.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.text.TextFormatting; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class List implements SlashHandler { 14 | @Override 15 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 16 | var languages = context.guildLocalizer().localizer().languages(); 17 | var builder = TextFormatting.getTableBuilder(languages, 18 | context.localize("words.language"), context.localize("words.code")); 19 | languages.forEach(lang -> builder.setNextRow(lang.getNativeName(), lang.getLocale())); 20 | event.reply(context.localize("command.locale.list.message.list") + "\n" + builder).complete(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repsettings/handler/name/Reset.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repsettings.handler.name; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Reset implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public Reset(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext eventContext) { 22 | guildRepository.guild(event.getGuild()).localeOverrides().removeOverride("words.reputation"); 23 | event.reply(eventContext.localize("command.repsettings.name.reset.message.reset")).setEphemeral(true).queue(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/de/chojo/repbot/dao/pagination/PageAccessTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.pagination; 7 | 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | 16 | class PageAccessTest { 17 | PageAccess access = new PageAccess<>(() -> 10, Collections::singletonList); 18 | 19 | @Test 20 | void pages() { 21 | assertEquals(10, access.pages()); 22 | } 23 | 24 | @Test 25 | void page() { 26 | for (int i = 0; i < 10; i++) { 27 | assertEquals(Collections.singletonList(i), access.page(i)); 28 | } 29 | } 30 | 31 | @Test 32 | void iterator() { 33 | int currPage = 0; 34 | for (var page : access) { 35 | assertEquals(Collections.singletonList(currPage++), page); 36 | } 37 | Assertions.assertEquals(currPage, 10); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/Redeploy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.util.Guilds; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Redeploy implements SlashHandler { 14 | @Override 15 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 16 | 17 | var guild = event.getJDA().getShardManager().getGuildById(event.getOption("guild_id").getAsLong()); 18 | 19 | if (guild == null) { 20 | event.reply("Guild not present.").setEphemeral(true).complete(); 21 | return; 22 | } 23 | 24 | event.reply("Refreshing commands of guild " + Guilds.prettyName(guild)).setEphemeral(true).complete(); 25 | context.interactionHub().refreshGuildCommands(guild); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/RemoveResetDate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler.resetdate; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class RemoveResetDate implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public RemoveResetDate(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | guildRepository.guild(event.getGuild()).settings().general().resetDate(null); 23 | 24 | event.reply(context.localize("command.repadmin.resetdate.remove.message.removed")).setEphemeral(true).complete(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/ranking/handler/guild/GuildGiven.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.ranking.handler.guild; 7 | 8 | import de.chojo.repbot.commands.ranking.handler.BaseTop; 9 | import de.chojo.repbot.config.Configuration; 10 | import de.chojo.repbot.dao.access.guild.RepGuild; 11 | import de.chojo.repbot.dao.access.guild.settings.sub.ReputationMode; 12 | import de.chojo.repbot.dao.pagination.Ranking; 13 | import de.chojo.repbot.dao.provider.GuildRepository; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | 16 | public class GuildGiven extends BaseTop { 17 | public GuildGiven(GuildRepository guildRepository, Configuration configuration) { 18 | super(guildRepository, configuration); 19 | } 20 | 21 | @Override 22 | protected Ranking buildRanking(SlashCommandInteractionEvent event, RepGuild guild, ReputationMode reputationMode, int pageSize) { 23 | return guild.reputation().ranking().given().byMode(reputationMode, pageSize); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/SetResetDateNow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler.resetdate; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class SetResetDateNow implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public SetResetDateNow(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | guildRepository.guild(event.getGuild()).settings().general().resetDateNow(); 23 | 24 | event.reply(context.localize("command.repadmin.resetdate.now.message.set")) 25 | .setEphemeral(true).complete(); 26 | } 27 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![wakatime](https://wakatime.com/badge/github/RainbowDashLabs/reputation-bot.svg)](https://wakatime.com/badge/github/RainbowDashLabs/reputation-bot) 2 | 3 | # Motivation 4 | 5 | This bot was created for the [DevCord Discord Server](https://discord.gg/gfEsr79d9a). \ 6 | We needed a way to identify valuable users in our community. Most bots do these by chat activity.\ 7 | Sadly a high chat activity doesn't mean that a user is valuable for the community.\ 8 | That is where the reputation bot comes in place. 9 | 10 | # How does it work 11 | 12 | The reputation bot will scan messages for thank phrases, which you can define.\ 13 | When a thank phrase is found the bot will try to find the receiver of the message. This is done by several checks. 14 | 15 | You can find more about the bot on our [website](https://rainbowdashlabs.github.io/reputation-bot/). 16 | 17 | # Self-hosting 18 | 19 | Take a look at our [hosting](https://rainbowdashlabs.github.io/reputation-bot/hosting/) page. 20 | 21 | # Invite and more Information 22 | 23 | For an invitation link and more information take a look at the [website](https://rainbowdashlabs.github.io/reputation-bot/invite/). 24 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/systemchannel/SystemChannelDisable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.systemchannel; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class SystemChannelDisable implements SlashHandler { 14 | private final GuildRepository guildRepository; 15 | 16 | public SystemChannelDisable(GuildRepository guildRepository) { 17 | this.guildRepository = guildRepository; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | guildRepository.guild(event.getGuild()).settings().general().systemChannel(0); 23 | event.reply(context.localize("command.channel.systemchannel.disable.message.disabled")).setEphemeral(true).queue(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/web/Api.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.web; 7 | 8 | import de.chojo.repbot.dao.provider.Metrics; 9 | import de.chojo.repbot.web.error.ApiException; 10 | import de.chojo.repbot.web.routes.v1.MetricsRoute; 11 | import io.javalin.Javalin; 12 | import io.javalin.apibuilder.ApiBuilder; 13 | import io.javalin.apibuilder.EndpointGroup; 14 | import io.javalin.router.Endpoint; 15 | import org.slf4j.Logger; 16 | 17 | import static io.javalin.apibuilder.ApiBuilder.before; 18 | import static io.javalin.apibuilder.ApiBuilder.path; 19 | import static org.slf4j.LoggerFactory.getLogger; 20 | 21 | public class Api { 22 | private static final Logger log = getLogger(Api.class); 23 | private final MetricsRoute metricsRoute; 24 | 25 | public Api(Metrics metrics) { 26 | metricsRoute = new MetricsRoute(metrics); 27 | } 28 | 29 | public void init() { 30 | before(ctx -> log.debug("Received request on {}.", ctx.path())); 31 | path("v1", () -> path("metrics", metricsRoute::buildRoutes)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/scan/handler/Cancel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.scan.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.commands.scan.util.Scanner; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Cancel implements SlashHandler { 14 | private final Scanner scanner; 15 | 16 | public Cancel(Scanner scanner) { 17 | this.scanner = scanner; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | if (!scanner.isActive(event.getGuild())) { 23 | event.reply(context.localize("command.scan.cancel.message.notask")).setEphemeral(true).complete(); 24 | return; 25 | } 26 | event.reply(context.localize("command.scan.cancel.message.canceling")).queue(); 27 | scanner.cancelScan(event.getGuild()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/Database.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | 9 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 10 | public class Database { 11 | private String host = "localhost"; 12 | private String port = "5432"; 13 | private String database = "postgres"; 14 | private String schema = "repbot_schema"; 15 | private String user = "postgres"; 16 | private String password = "postgres"; 17 | private int poolSize = 5; 18 | 19 | public String host() { 20 | return host; 21 | } 22 | 23 | public String port() { 24 | return port; 25 | } 26 | 27 | public String database() { 28 | return database; 29 | } 30 | 31 | public String schema() { 32 | return schema; 33 | } 34 | 35 | public String user() { 36 | return user; 37 | } 38 | 39 | public String password() { 40 | return password; 41 | } 42 | 43 | public int poolSize() { 44 | return poolSize; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/LogNotify.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import org.jetbrains.annotations.NotNull; 9 | import org.slf4j.Marker; 10 | import org.slf4j.MarkerFactory; 11 | 12 | public final class LogNotify { 13 | /** 14 | * Will be send to error-log channel. 15 | */ 16 | public static final Marker NOTIFY_ADMIN = createMarker("NOTIFY_ADMIN"); 17 | /** 18 | * Will be sent to status-log. 19 | */ 20 | public static final Marker STATUS = createMarker("STATUS"); 21 | /** 22 | * Currently unused. 23 | */ 24 | public static final Marker DISCORD = createMarker("DISCORD"); 25 | 26 | private LogNotify() { 27 | throw new UnsupportedOperationException("This is a utility class."); 28 | } 29 | 30 | private static Marker createMarker(@NotNull String name, @NotNull Marker... children) { 31 | var marker = MarkerFactory.getMarker(name); 32 | for (var child : children) { 33 | marker.add(child); 34 | } 35 | return marker; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/profile/Profile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.profile; 7 | 8 | import de.chojo.jdautil.interactions.slash.Argument; 9 | import de.chojo.jdautil.interactions.slash.Slash; 10 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 11 | import de.chojo.repbot.config.Configuration; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import de.chojo.repbot.service.RoleAssigner; 14 | 15 | public class Profile extends SlashCommand { 16 | public Profile(GuildRepository guildRepository, Configuration configuration, RoleAssigner roleAssigner) { 17 | super(Slash.of("profile", "command.profile.description") 18 | .guildOnly() 19 | .command(new de.chojo.repbot.commands.profile.handler.Profile(guildRepository, configuration, roleAssigner)) 20 | .argument(Argument.user("user", "command.profile.options.user.description")) 21 | .argument(Argument.bool("detailed", "command.profile.options.detailed.description")) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/ResultEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots; 7 | 8 | import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.snapshots.analyzer.ResultSnapshot; 12 | import net.dv8tion.jda.api.entities.Guild; 13 | import net.dv8tion.jda.api.entities.Message; 14 | import net.dv8tion.jda.api.entities.MessageEmbed; 15 | 16 | public record ResultEntry(ResultSnapshot result, long channelId, long messageId) { 17 | public MessageEmbed embed(Guild guild, EventContext context) { 18 | var builder = new LocalizedEmbedBuilder(context.guildLocalizer()) 19 | .setAuthor("command.log.analyzer.message.author", 20 | Message.JUMP_URL.formatted(guild.getIdLong(), channelId, messageId), 21 | Replacement.create("ID", messageId())); 22 | result.add(guild, this, builder); 23 | return builder.build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/ranking/handler/guild/GuildReceived.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.ranking.handler.guild; 7 | 8 | import de.chojo.repbot.commands.ranking.handler.BaseTop; 9 | import de.chojo.repbot.config.Configuration; 10 | import de.chojo.repbot.dao.access.guild.RepGuild; 11 | import de.chojo.repbot.dao.access.guild.settings.sub.ReputationMode; 12 | import de.chojo.repbot.dao.pagination.Ranking; 13 | import de.chojo.repbot.dao.provider.GuildRepository; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | 16 | public class GuildReceived extends BaseTop { 17 | 18 | public GuildReceived(GuildRepository guildRepository, Configuration configuration, boolean premium) { 19 | super(guildRepository, configuration, premium); 20 | } 21 | 22 | @Override 23 | protected Ranking buildRanking(SlashCommandInteractionEvent event, RepGuild guild, ReputationMode reputationMode, int pageSize) { 24 | return guild.reputation().ranking().received().byMode(reputationMode, pageSize); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/display/SystemInfoStatisticDisplay.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic.display; 7 | 8 | import de.chojo.repbot.statistic.EmbedDisplay; 9 | import de.chojo.repbot.statistic.element.DataStatistic; 10 | import de.chojo.repbot.statistic.element.ShardCountStatistic; 11 | import net.dv8tion.jda.api.EmbedBuilder; 12 | 13 | public record SystemInfoStatisticDisplay(ShardCountStatistic shardCountStatistic, 14 | DataStatistic dataStatistic) implements EmbedDisplay { 15 | 16 | @Override 17 | public void appendTo(EmbedBuilder embedBuilder) { 18 | embedBuilder.setTitle("System Info") 19 | .appendDescription( 20 | String.format("Watching %s guilds on %s shard/s\n%s/%s active channel on %s active guilds.", 21 | dataStatistic.guilds(), shardCountStatistic.shardCount(), 22 | dataStatistic.activeChannel(), dataStatistic.channel(), dataStatistic.activeGuilds())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tags/context.md: -------------------------------------------------------------------------------- 1 | ### What is a context? 2 | 3 | In order to resolve targets of a message and check which users are qualified to receive reputation, we build a context. 4 | This context contains all users which are qualified to receive reputation and is build for every message when the bot 5 | detects a thankword. 6 | 7 | If you are interested in how it works, here is a short explanation: 8 | To build the message context we search for the oldest message within a fixed time (This is the max message age. 30 9 | minutes on default). 10 | After we found the older message of the reputation donor we collect all users which have written a message after the 11 | oldest message. If we haven't found any message within the max message age we add the users of the last 10 messages (The 12 | amount depends on the server settings) to the context. We do this because often users come back after some time and the 13 | thank duration already ran out. 14 | Finally we add also the users which share a voice channel with the message author and the users which shared a voice 15 | channel with the users withing the max message age. 16 | 17 | You can read more about this mechanic on our [abuse protection page](abuse_protection.md) 18 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/log/Analyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.log; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.parsing.ValueParser; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.commands.log.handler.BaseAnalyzer; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 14 | 15 | public class Analyzer extends BaseAnalyzer implements SlashHandler { 16 | private final GuildRepository guildRepository; 17 | 18 | public Analyzer(GuildRepository guildRepository) { 19 | this.guildRepository = guildRepository; 20 | } 21 | 22 | @Override 23 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 24 | var guild_id = ValueParser.parseLong(event.getOption("guild_id").getAsString()); 25 | onSlashCommand(event, context, guildRepository.byId(guild_id.get()).reputation()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/match/DirectAnalyzerResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results.match; 7 | 8 | import de.chojo.repbot.dao.snapshots.analyzer.ResultSnapshot; 9 | import de.chojo.repbot.dao.snapshots.analyzer.match.DirectResultSnapshot; 10 | import net.dv8tion.jda.api.entities.Member; 11 | 12 | import java.util.List; 13 | 14 | public class DirectAnalyzerResult extends MatchAnalyzerResult { 15 | private final List receivers; 16 | 17 | public DirectAnalyzerResult(String match, ThankType type, Member donor, List receivers) { 18 | super(type, donor, match); 19 | this.receivers = receivers; 20 | } 21 | 22 | protected List receiverIds() { 23 | return receivers.stream().map(Member::getIdLong).toList(); 24 | } 25 | 26 | @Override 27 | public List receivers() { 28 | return receivers; 29 | } 30 | 31 | @Override 32 | public ResultSnapshot toSnapshot() { 33 | return new DirectResultSnapshot(thankType(), donorId(), match(), receiverIds()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/exceptions/MissingSupportTier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.exceptions; 7 | 8 | import de.chojo.jdautil.interactions.base.SkuMeta; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.repbot.util.SupporterFeature; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MissingSupportTier extends RuntimeException { 16 | private SupporterFeature type; 17 | private SkuMeta requiredTier; 18 | private Replacement[] replacements; 19 | 20 | public MissingSupportTier(SupporterFeature type, SkuMeta requiredTier, Replacement... replacements) { 21 | super("", null, true, false); 22 | this.type = type; 23 | this.requiredTier = requiredTier; 24 | this.replacements = replacements; 25 | } 26 | 27 | public SupporterFeature type() { 28 | return type; 29 | } 30 | 31 | public SkuMeta requiredTier() { 32 | return requiredTier; 33 | } 34 | 35 | public List replacements() { 36 | return Arrays.stream(replacements).toList(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/element/ShardCountStatistic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic.element; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.repbot.statistic.EmbedDisplay; 10 | import de.chojo.repbot.statistic.ReplacementProvider; 11 | import net.dv8tion.jda.api.EmbedBuilder; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | public record ShardCountStatistic(List shardStatistics) implements ReplacementProvider, EmbedDisplay { 17 | 18 | public int shardCount() { 19 | return shardStatistics.size(); 20 | } 21 | 22 | @Override 23 | public List replacements() { 24 | return Collections.singletonList(Replacement.create("shard_count", shardCount())); 25 | } 26 | 27 | @Override 28 | public void appendTo(EmbedBuilder embedBuilder) { 29 | for (var shard : shardStatistics) { 30 | embedBuilder.addField("#" + shard.shard(), 31 | "Status: " + shard.status().name() + "\nGuilds:" + shard.guilds(), true); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/user/received/handler/ReceivedReputation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.user.received.handler; 7 | 8 | import de.chojo.jdautil.interactions.user.UserHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.commands.log.handler.Received; 11 | import de.chojo.repbot.config.Configuration; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; 14 | 15 | public class ReceivedReputation implements UserHandler { 16 | private final GuildRepository guildRepository; 17 | private final Configuration configuration; 18 | 19 | public ReceivedReputation(GuildRepository guildRepository, Configuration configuration) { 20 | this.guildRepository = guildRepository; 21 | this.configuration = configuration; 22 | } 23 | 24 | 25 | @Override 26 | public void onUser(UserContextInteractionEvent event, EventContext eventContext) { 27 | Received.send(event, event.getTargetMember(), guildRepository, eventContext, configuration); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/system/Reload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.system; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.config.Configuration; 11 | import de.chojo.repbot.config.exception.ConfigurationException; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class Reload implements SlashHandler { 15 | 16 | private final Configuration configuration; 17 | 18 | public Reload(Configuration configuration) { 19 | this.configuration = configuration; 20 | } 21 | 22 | @Override 23 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 24 | try { 25 | configuration.reload(); 26 | } catch (ConfigurationException e) { 27 | event.reply("Config reload failed").setEphemeral(true).complete(); 28 | return; 29 | } 30 | event.reply("Config file reloaded.").setEphemeral(true).complete(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/user/donated/received/handler/DonatedReputation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.user.donated.received.handler; 7 | 8 | import de.chojo.jdautil.interactions.user.UserHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.commands.log.handler.Donated; 11 | import de.chojo.repbot.config.Configuration; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; 14 | 15 | public class DonatedReputation implements UserHandler { 16 | private final GuildRepository guildRepository; 17 | private final Configuration configuration; 18 | 19 | public DonatedReputation(GuildRepository guildRepository, Configuration configuration) { 20 | this.guildRepository = guildRepository; 21 | this.configuration = configuration; 22 | } 23 | 24 | 25 | @Override 26 | public void onUser(UserContextInteractionEvent event, EventContext eventContext) { 27 | Donated.send(event, event.getTargetMember(), guildRepository, eventContext, configuration); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | 1. Head to Server Settings -> Integrations. Click to manage the reputation bot and add at least one role which 4 | should be allowed to manage the bot. 5 | 2. Execute the `/setup` command and follow the instructions, which will guide you through the basic setup 6 | 7 | After this, there are some optional steps you may want to take a look at. You will find more in depth configuration 8 | possibilities on the [configuration and customization page](configuration.md) 9 | 10 | - Use the `/scan` command to scan the messages in a channel for thank phrases. This will backfill your reputations. You 11 | can scan up to 100k messages in a channel. This will take some time, and you can only scan one channel at a time. 12 | The scan might cancel at some time once discord takes too long to deliver the requested messages. 13 | - Set your own reputation emote with `/reaction main`. This can be a custom emote from your server or a normal 14 | discord emote. you can also add more additional emotes with `/reactions add`. 15 | - Set the legacy prefix. All slash commands also exists as legacy text commands. 16 | - Use the `/repsettings` command to tweak your settings. 17 | - User the `/thankwords check` command to check if a message would give reputation. 18 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/Search.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.util.Guilds; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | import java.util.Locale; 14 | import java.util.stream.Collectors; 15 | 16 | public class Search implements SlashHandler { 17 | @Override 18 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 19 | var term = event.getOption("term").getAsString().toLowerCase(Locale.ROOT); 20 | 21 | event.deferReply(true).complete(); 22 | 23 | var guilds = event.getJDA().getShardManager().getGuildCache() 24 | .stream().filter(guild -> guild.getName().toLowerCase(Locale.ROOT).contains(term)) 25 | .map(Guilds::prettyName) 26 | .collect(Collectors.joining("\n")); 27 | 28 | event.getHook().editOriginal(guilds).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/messages/log/MessageLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.messages.log; 7 | 8 | import de.chojo.jdautil.interactions.message.Message; 9 | import de.chojo.jdautil.interactions.message.provider.MessageProvider; 10 | import de.chojo.repbot.actions.messages.log.handler.MessageAnalyzer; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.Permission; 13 | import net.dv8tion.jda.api.interactions.InteractionContextType; 14 | 15 | import java.util.Set; 16 | 17 | public class MessageLog implements MessageProvider { 18 | private final GuildRepository guildRepository; 19 | 20 | public MessageLog(GuildRepository guildRepository) { 21 | this.guildRepository = guildRepository; 22 | } 23 | 24 | @Override 25 | public Message message() { 26 | return Message.of("Message Log") 27 | .handler(new MessageAnalyzer(guildRepository)) 28 | .setContext(Set.of(InteractionContextType.GUILD)) 29 | .withPermission(Permission.MESSAGE_MANAGE) 30 | .build(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/Cleanup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 9 | public class Cleanup { 10 | private int analyzerLogHours = 24; 11 | private int gdprDays = 90; 12 | private int voiceActivityHours = 24; 13 | 14 | private int cleanupScheduleDays = 14; 15 | 16 | /** 17 | * The hours after an entry in the analyzer_log table gets deleted. 18 | */ 19 | public int analyzerLogHours() { 20 | return analyzerLogHours; 21 | } 22 | 23 | /** 24 | * The days after an entry in the gdpr_log table gets deleted. 25 | */ 26 | public int gdprDays() { 27 | return gdprDays; 28 | } 29 | 30 | /** 31 | * The hours after an entry in the voice_activity table gets deleted. 32 | */ 33 | public int voiceActivityHours() { 34 | return voiceActivityHours; 35 | } 36 | 37 | /** 38 | * The days after an entry in the cleanup_schedule table gets deleted. 39 | */ 40 | public int cleanupScheduleDays() { 41 | return cleanupScheduleDays; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.statistics; 7 | 8 | import de.chojo.sadu.mapper.wrapper.Row; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.sql.SQLException; 12 | import java.time.LocalDate; 13 | 14 | public record DowStatistics(LocalDate date, int dow, int count) implements Comparable { 15 | 16 | public static DowStatistics build(Row rs, String dateKey) throws SQLException { 17 | return new DowStatistics(rs.getDate(dateKey).toLocalDate(), rs.getInt("dow"), 18 | rs.getInt("count")); 19 | } 20 | 21 | @Override 22 | public int compareTo(@NotNull DowStatistics o) { 23 | return date().compareTo(o.date()); 24 | } 25 | 26 | public String dowAsString() { 27 | return switch (dow()) { 28 | case 1 -> "Monday"; 29 | case 2 -> "Tuesday"; 30 | case 3 -> "Wednesday"; 31 | case 4 -> "Thursday"; 32 | case 5 -> "Friday"; 33 | case 6 -> "Saturday"; 34 | case 7 -> "Sunday"; 35 | default -> ""; 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/de/chojo/repbot/dao/access/guild/reputation/sub/AnalyzerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.reputation.sub; 7 | 8 | import de.chojo.repbot.service.reputation.SubmitResult; 9 | import org.intellij.lang.annotations.Language; 10 | import org.junit.jupiter.api.Assertions; 11 | import org.junit.jupiter.api.Test; 12 | 13 | class AnalyzerTest { 14 | 15 | @Test 16 | void deserialize() { 17 | @Language("json") 18 | var str = """ 19 | { 20 | "type": "SUBMITTING", 21 | "replacements": [ 22 | { 23 | "key": "%type%", 24 | "value": "$thankType.direct.name$", 25 | "caseSensitive": false 26 | }, 27 | { 28 | "key": "%USER%", 29 | "value": "<@816604004497752145>", 30 | "caseSensitive": false 31 | } 32 | ] 33 | } 34 | """; 35 | Assertions.assertDoesNotThrow(() -> Analyzer.MAPPER.readValue(str, SubmitResult.class)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Add.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler.reputation; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.access.guild.reputation.sub.RepUser; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import de.chojo.repbot.service.RoleAssigner; 13 | import net.dv8tion.jda.api.entities.User; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | 16 | public class Add extends BaseReputationModifier { 17 | 18 | public Add(RoleAssigner roleAssigner, GuildRepository guildRepository) { 19 | super(roleAssigner, guildRepository); 20 | } 21 | 22 | @Override 23 | void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { 24 | repUser.addReputation(rep); 25 | event.reply(context.localize("command.repadmin.reputation.add.message.added", 26 | Replacement.create("VALUE", rep), Replacement.createMention(user))) 27 | .setEphemeral(true).complete(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Set.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler.reputation; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.access.guild.reputation.sub.RepUser; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import de.chojo.repbot.service.RoleAssigner; 13 | import net.dv8tion.jda.api.entities.User; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | 16 | public class Set extends BaseReputationModifier { 17 | 18 | public Set(RoleAssigner roleAssigner, GuildRepository guildRepository) { 19 | super(roleAssigner, guildRepository); 20 | } 21 | 22 | @Override 23 | void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { 24 | repUser.setReputation(rep); 25 | event.reply(context.localize("command.repadmin.reputation.set.message.set", 26 | Replacement.create("VALUE", rep), Replacement.createMention(user))) 27 | .setEphemeral(true).complete(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/gdpr/handler/Delete.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.gdpr.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.access.Gdpr; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | import org.slf4j.Logger; 13 | 14 | import static org.slf4j.LoggerFactory.getLogger; 15 | 16 | public class Delete implements SlashHandler { 17 | private final Gdpr gdpr; 18 | private static final Logger log = getLogger(Delete.class); 19 | 20 | public Delete(Gdpr gdpr) { 21 | this.gdpr = gdpr; 22 | } 23 | 24 | @Override 25 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 26 | var success = gdpr.request(event.getUser()).queueDeletion(); 27 | if (success) { 28 | event.reply(context.localize("command.gdpr.delete.message.received")).setEphemeral(true).complete(); 29 | } else { 30 | event.reply(context.localize("command.gdpr.delete.message.scheduled")).setEphemeral(true).complete(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/abuseprotection/handler/cooldown/OnceCooldown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.abuseprotection.handler.cooldown; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class OnceCooldown implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | 17 | public OnceCooldown(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | var guild = guildRepository.guild(event.getGuild()); 24 | var abuseSettings = guild.settings().abuseProtection(); 25 | 26 | event.reply(context.localize("command.abuseprotection.cooldown.once.message.set", 27 | Replacement.create("MINUTES", abuseSettings.cooldown(-1)))).setEphemeral(true).queue(); 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Remove.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler.reputation; 7 | 8 | import de.chojo.jdautil.localization.util.Replacement; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.access.guild.reputation.sub.RepUser; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import de.chojo.repbot.service.RoleAssigner; 13 | import net.dv8tion.jda.api.entities.User; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | 16 | public class Remove extends BaseReputationModifier { 17 | 18 | public Remove(RoleAssigner roleAssigner, GuildRepository guildRepository) { 19 | super(roleAssigner, guildRepository); 20 | } 21 | 22 | @Override 23 | void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { 24 | repUser.removeReputation(rep); 25 | event.reply(context.localize("command.repadmin.reputation.remove.message.removed", 26 | Replacement.create("VALUE", rep), Replacement.createMention(user))) 27 | .setEphemeral(true).complete(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/roles/handler/donor/AddDonor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.roles.handler.donor; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | import java.util.Collections; 15 | 16 | public class AddDonor implements SlashHandler { 17 | private final GuildRepository guildRepository; 18 | 19 | public AddDonor(GuildRepository guildRepository) { 20 | this.guildRepository = guildRepository; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | var role = event.getOption("role").getAsRole(); 26 | guildRepository.guild(event.getGuild()).settings().thanking().donorRoles().add(role); 27 | event.reply(context.localize("command.roles.donor.add.message.add", 28 | Replacement.createMention(role))).setAllowedMentions(Collections.emptyList()).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/util/FilterUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.util; 7 | 8 | import net.dv8tion.jda.api.Permission; 9 | import net.dv8tion.jda.api.entities.Guild; 10 | import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; 11 | 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | public final class FilterUtil { 16 | 17 | private FilterUtil() { 18 | throw new UnsupportedOperationException("This is a utility class."); 19 | } 20 | 21 | /** 22 | * Get all channel where the bot user can write and read. 23 | * 24 | * @param guild guild 25 | * @return list of accessable text channel 26 | */ 27 | public static List getAccessableTextChannel(Guild guild) { 28 | return filterChannelByPermission(guild, Permission.VIEW_CHANNEL, Permission.MESSAGE_SEND); 29 | } 30 | 31 | public static List filterChannelByPermission(Guild guild, Permission... permissions) { 32 | var self = guild.getSelfMember(); 33 | return guild.getTextChannels().stream().filter(textChannel -> self.hasPermission(textChannel, permissions)) 34 | .collect(Collectors.toList()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/match/fuzzy/MemberMatch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results.match.fuzzy; 7 | 8 | import com.fasterxml.jackson.annotation.JsonCreator; 9 | import com.fasterxml.jackson.annotation.JsonProperty; 10 | 11 | public class MemberMatch { 12 | private final String word; 13 | private final String name; 14 | private final String nickname; 15 | private final double score; 16 | 17 | @JsonCreator 18 | public MemberMatch(@JsonProperty("word") String word, @JsonProperty("name") String name, @JsonProperty("nickname") String nickname, @JsonProperty("score") double score) { 19 | this.word = word; 20 | this.name = name; 21 | this.nickname = nickname; 22 | this.score = score; 23 | } 24 | 25 | public String word() { 26 | return word; 27 | } 28 | 29 | public String name() { 30 | return name; 31 | } 32 | 33 | public String nickname() { 34 | return nickname; 35 | } 36 | 37 | public double score() { 38 | return score; 39 | } 40 | 41 | public String asString() { 42 | return "`%s` ➜ %s (%s) | Score %.03f".formatted(word, name, nickname, score); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/roles/handler/donor/RemoveDonor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.roles.handler.donor; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | import java.util.Collections; 15 | 16 | public class RemoveDonor implements SlashHandler { 17 | private final GuildRepository guildRepository; 18 | 19 | public RemoveDonor(GuildRepository guildRepository) { 20 | this.guildRepository = guildRepository; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | var role = event.getOption("role").getAsRole(); 26 | guildRepository.guild(event.getGuild()).settings().thanking().donorRoles().remove(role); 27 | event.reply(context.localize("command.roles.donor.remove.message.remove", 28 | Replacement.createMention(role))).setAllowedMentions(Collections.emptyList()).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/roles/handler/receiver/AddReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.roles.handler.receiver; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | import java.util.Collections; 15 | 16 | public class AddReceiver implements SlashHandler { 17 | private final GuildRepository guildRepository; 18 | 19 | public AddReceiver(GuildRepository guildRepository) { 20 | this.guildRepository = guildRepository; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | var role = event.getOption("role").getAsRole(); 26 | guildRepository.guild(event.getGuild()).settings().thanking().receiverRoles().add(role); 27 | event.reply(context.localize("command.roles.receiver.add.message.add", 28 | Replacement.createMention(role))).setAllowedMentions(Collections.emptyList()).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/autopost/AutopostDisable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.autopost; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import de.chojo.repbot.service.AutopostService; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class AutopostDisable implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | private final AutopostService autopostService; 17 | 18 | public AutopostDisable(GuildRepository guildRepository, AutopostService autopostService) { 19 | this.guildRepository = guildRepository; 20 | this.autopostService = autopostService; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | guildRepository.guild(event.getGuild()).settings().autopost().active(false); 26 | autopostService.delete(event.getGuild()); 27 | event.reply("command.channel.autopost.disable.message.disabled").setEphemeral(true).queue(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/roles/handler/receiver/RemoveReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.roles.handler.receiver; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | import java.util.Collections; 15 | 16 | public class RemoveReceiver implements SlashHandler { 17 | private final GuildRepository guildRepository; 18 | 19 | public RemoveReceiver(GuildRepository guildRepository) { 20 | this.guildRepository = guildRepository; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | var role = event.getOption("role").getAsRole(); 26 | guildRepository.guild(event.getGuild()).settings().thanking().receiverRoles().remove(role); 27 | event.reply(context.localize("command.roles.receiver.remove.message.remove", 28 | Replacement.createMention(role))).setAllowedMentions(Collections.emptyList()).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/statistic/display/GlobalInfoStatisticDisplay.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.statistic.display; 7 | 8 | import de.chojo.repbot.statistic.EmbedDisplay; 9 | import de.chojo.repbot.statistic.element.DataStatistic; 10 | import de.chojo.repbot.statistic.element.GlobalShardStatistic; 11 | import net.dv8tion.jda.api.EmbedBuilder; 12 | 13 | public record GlobalInfoStatisticDisplay(GlobalShardStatistic globalShardStatistic, 14 | DataStatistic dataStatistic) implements EmbedDisplay { 15 | 16 | 17 | @Override 18 | public void appendTo(EmbedBuilder embedBuilder) { 19 | embedBuilder.addField("Global Info", 20 | String.format(""" 21 | Analyzed: %s 22 | Total Reputation: %s 23 | Week Reputation: %s 24 | AverageWeek Reputation: %s 25 | Today Reputation: %s 26 | """.stripIndent(), 27 | globalShardStatistic.analyzedMessages(), dataStatistic.totalRep(), dataStatistic.weeklyRep(), 28 | dataStatistic.weeklyAvgRep(), dataStatistic.today()), false); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/prune/handler/Guild.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.prune.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.service.GdprService; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | import org.slf4j.Logger; 14 | 15 | import static org.slf4j.LoggerFactory.getLogger; 16 | 17 | public class Guild implements SlashHandler { 18 | private static final Logger log = getLogger(Guild.class); 19 | private final GdprService service; 20 | 21 | public Guild(GdprService service) { 22 | this.service = service; 23 | } 24 | 25 | @Override 26 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 27 | event.reply(context.localize("command.prune.guild.message.started")).complete(); 28 | service.cleanupGuildUsers(event.getGuild()) 29 | .thenAccept(amount -> event.getHook().editOriginal(context.localize("command.prune.guild.message.done", 30 | Replacement.create("AMOUNT", amount))).complete()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/repadmin/handler/Profile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.repadmin.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.config.Configuration; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class Profile implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | private final Configuration configuration; 17 | 18 | public Profile(GuildRepository guildRepository, Configuration configuration) { 19 | this.guildRepository = guildRepository; 20 | this.configuration = configuration; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | event.deferReply(true).complete(); 26 | var user = guildRepository.guild(event.getGuild()).reputation().user(event.getOption("user").getAsMember()); 27 | var profile = user.profile().adminProfile(configuration, context.guildLocalizer()); 28 | event.getHook().editOriginalEmbeds(profile).complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/SKU.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | import de.chojo.jdautil.interactions.premium.SKUConfiguration; 9 | import de.chojo.repbot.config.elements.sku.SKUFeatures; 10 | import de.chojo.repbot.config.elements.sku.Subscription; 11 | 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) 17 | public class SKU { 18 | List subscriptions = List.of(new Subscription()); 19 | SKUConfiguration interactions = new SKUConfiguration(); 20 | SKUFeatures features = new SKUFeatures(); 21 | 22 | int subscriptionErrorMessageHours = 36; 23 | int errorThresholdBlock = 10; 24 | 25 | 26 | public SKUConfiguration interactions() { 27 | return interactions; 28 | } 29 | 30 | public SKUFeatures features() { 31 | return features; 32 | } 33 | 34 | public int subscriptionErrorMessageHours() { 35 | return subscriptionErrorMessageHours; 36 | } 37 | 38 | public int errorThresholdBlock() { 39 | return errorThresholdBlock; 40 | } 41 | 42 | public List subscriptions() { 43 | return subscriptions; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/abuseprotection/handler/cooldown/SetCooldown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.abuseprotection.handler.cooldown; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class SetCooldown implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | 17 | public SetCooldown(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | var guild = guildRepository.guild(event.getGuild()); 24 | var abuseSettings = guild.settings().abuseProtection(); 25 | var cooldown = event.getOption("minutes").getAsLong(); 26 | 27 | event.reply(context.localize("command.abuseprotection.cooldown.set.message.set", 28 | Replacement.create("MINUTES", abuseSettings.cooldown((int) cooldown)))).setEphemeral(true).queue(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/info/Info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.info; 7 | 8 | import de.chojo.jdautil.interactions.slash.Slash; 9 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 10 | import de.chojo.repbot.commands.info.handler.Show; 11 | import de.chojo.repbot.config.Configuration; 12 | import org.slf4j.Logger; 13 | 14 | import java.io.IOException; 15 | import java.nio.charset.StandardCharsets; 16 | 17 | import static org.slf4j.LoggerFactory.getLogger; 18 | 19 | public class Info extends SlashCommand { 20 | private static final Logger log = getLogger(Info.class); 21 | 22 | private Info(String version, Configuration configuration) { 23 | super(Slash.of("info", "command.info.description") 24 | .command(new Show(version, configuration))); 25 | } 26 | 27 | public static Info create(Configuration configuration) { 28 | var version = "undefined"; 29 | try (var input = Info.class.getClassLoader().getResourceAsStream("version")) { 30 | version = new String(input.readAllBytes(), StandardCharsets.UTF_8).trim(); 31 | } catch (IOException e) { 32 | log.error("Could not determine version."); 33 | } 34 | return new Info(version, configuration); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.analyzer.results.empty; 7 | 8 | import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; 9 | import de.chojo.repbot.analyzer.results.AnalyzerResult; 10 | import de.chojo.repbot.analyzer.results.ResultType; 11 | import de.chojo.repbot.dao.snapshots.analyzer.ResultSnapshot; 12 | import de.chojo.repbot.dao.snapshots.ResultEntry; 13 | import de.chojo.repbot.util.Colors; 14 | import net.dv8tion.jda.api.entities.Guild; 15 | 16 | import javax.annotation.Nullable; 17 | 18 | public record EmptyAnalyzerResult(@Nullable String match, EmptyResultReason reason) implements AnalyzerResult, ResultSnapshot { 19 | 20 | @Override 21 | public ResultType resultType() { 22 | return ResultType.NO_MATCH; 23 | } 24 | 25 | @Override 26 | public ResultSnapshot toSnapshot() { 27 | return this; 28 | } 29 | 30 | @Override 31 | public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { 32 | builder.setTitle(reason.localeKey()) 33 | .setColor(Colors.Pastel.ORANGE); 34 | if (match != null) { 35 | builder.addField("command.log.analyzer.message.field.matchedWord", match, false); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/elements/SelfCleanup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.elements; 7 | 8 | import java.time.Instant; 9 | import java.time.LocalDateTime; 10 | import java.time.OffsetDateTime; 11 | import java.time.ZoneOffset; 12 | import java.time.temporal.ChronoUnit; 13 | 14 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) 15 | public class SelfCleanup { 16 | private boolean active = true; 17 | private int promptDays = 3; 18 | private int leaveDays = 3; 19 | private int inactiveDays = 90; 20 | 21 | public boolean isActive() { 22 | return active; 23 | } 24 | 25 | public int promptDays() { 26 | return promptDays; 27 | } 28 | 29 | public int leaveDays() { 30 | return leaveDays; 31 | } 32 | 33 | public int inactiveDays() { 34 | return inactiveDays; 35 | } 36 | 37 | public OffsetDateTime getPromptDaysOffset() { 38 | return LocalDateTime.now().minusDays(promptDays()).atOffset(ZoneOffset.UTC); 39 | } 40 | 41 | public LocalDateTime getLeaveDaysOffset() { 42 | return LocalDateTime.now().minusDays(leaveDays()); 43 | } 44 | 45 | public Instant getInactiveDaysOffset() { 46 | return Instant.now().minus(inactiveDays(), ChronoUnit.DAYS); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/autopost/RefreshInterval.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.settings.sub.autopost; 7 | 8 | import java.time.LocalDateTime; 9 | import java.time.temporal.ChronoField; 10 | import java.util.function.Predicate; 11 | 12 | public enum RefreshInterval { 13 | /** 14 | * Send on every full hour. 15 | */ 16 | HOURLY(now -> true), 17 | /** 18 | * Send at midnight UTC. 19 | */ 20 | DAILY(now -> now.getHour() == 0), 21 | /** 22 | * Send at midnight UTC every Monday. 23 | */ 24 | WEEKLY(now -> now.get(ChronoField.DAY_OF_WEEK) == 1 && now.getHour() == 0), 25 | /** 26 | * Send at midnight UTC every first day of the month. 27 | */ 28 | MONTHLY(now -> now.getDayOfMonth() == 1 && now.getHour() == 0); 29 | 30 | private final Predicate applicable; 31 | 32 | RefreshInterval(Predicate applicable) { 33 | this.applicable = applicable; 34 | } 35 | 36 | public boolean isApplicable(LocalDateTime now) { 37 | return applicable.test(now); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "%s.%s.name".formatted(getClass().getSimpleName().toLowerCase(), name().toLowerCase()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/ranking/UserRankings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.access.guild.reputation.sub.ranking; 7 | 8 | import de.chojo.repbot.dao.access.guild.reputation.sub.Rankings; 9 | import de.chojo.repbot.dao.access.guild.reputation.sub.ranking.user.UserGiven; 10 | import de.chojo.repbot.dao.access.guild.reputation.sub.ranking.user.UserReceived; 11 | import de.chojo.repbot.dao.components.GuildHolder; 12 | import net.dv8tion.jda.api.entities.Guild; 13 | 14 | public class UserRankings implements GuildHolder { 15 | private final Rankings rankings; 16 | private final UserReceived userReceived = new UserReceived(this); 17 | private final UserGiven userGiven = new UserGiven(this); 18 | 19 | public UserRankings(Rankings rankings) { 20 | this.rankings = rankings; 21 | } 22 | 23 | @Override 24 | public Guild guild() { 25 | return rankings.guild(); 26 | } 27 | 28 | @Override 29 | public long guildId() { 30 | return rankings.guildId(); 31 | } 32 | 33 | public Rankings ranking() { 34 | return rankings; 35 | } 36 | 37 | public UserReceived received() { 38 | return userReceived; 39 | } 40 | 41 | public UserGiven given() { 42 | return userGiven; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/user/donated/received/UserDonated.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.user.donated.received; 7 | 8 | import de.chojo.jdautil.interactions.user.User; 9 | import de.chojo.jdautil.interactions.user.provider.UserProvider; 10 | import de.chojo.repbot.actions.user.donated.received.handler.DonatedReputation; 11 | import de.chojo.repbot.config.Configuration; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import net.dv8tion.jda.api.Permission; 14 | import net.dv8tion.jda.api.interactions.InteractionContextType; 15 | 16 | import java.util.Set; 17 | 18 | public class UserDonated implements UserProvider { 19 | private final GuildRepository guildRepository; 20 | private final Configuration configuration; 21 | 22 | public UserDonated(GuildRepository guildRepository, Configuration configuration) { 23 | this.guildRepository = guildRepository; 24 | this.configuration = configuration; 25 | } 26 | 27 | @Override 28 | public User user() { 29 | return User.of("Given Reputation").handler(new DonatedReputation(guildRepository, configuration)) 30 | .setContext(Set.of(InteractionContextType.GUILD)) 31 | .withPermission(Permission.MESSAGE_MANAGE) 32 | .build(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/listener/VoiceStateListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.listener; 7 | 8 | import de.chojo.repbot.dao.provider.Voice; 9 | import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; 10 | import net.dv8tion.jda.api.hooks.ListenerAdapter; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.concurrent.ScheduledExecutorService; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | public class VoiceStateListener extends ListenerAdapter implements Runnable { 17 | private final Voice voice; 18 | 19 | public VoiceStateListener(Voice voice) { 20 | this.voice = voice; 21 | } 22 | 23 | public static VoiceStateListener of(Voice voice, ScheduledExecutorService repBotWorker) { 24 | var voiceStateListener = new VoiceStateListener(voice); 25 | repBotWorker.scheduleAtFixedRate(voiceStateListener, 2, 12, TimeUnit.HOURS); 26 | return voiceStateListener; 27 | } 28 | 29 | @Override 30 | public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { 31 | if (event.getChannelLeft() != null) { 32 | voice.logUser(event.getMember(), event.getChannelLeft().getMembers()); 33 | } 34 | } 35 | 36 | @Override 37 | public void run() { 38 | voice.cleanup(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/ranking/handler/user/UserGiven.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.ranking.handler.user; 7 | 8 | import de.chojo.repbot.commands.ranking.handler.BaseTop; 9 | import de.chojo.repbot.config.Configuration; 10 | import de.chojo.repbot.dao.access.guild.RepGuild; 11 | import de.chojo.repbot.dao.access.guild.settings.sub.ReputationMode; 12 | import de.chojo.repbot.dao.pagination.Ranking; 13 | import de.chojo.repbot.dao.provider.GuildRepository; 14 | import net.dv8tion.jda.api.entities.Member; 15 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 16 | import net.dv8tion.jda.api.interactions.commands.OptionMapping; 17 | 18 | import java.util.Optional; 19 | 20 | public class UserGiven extends BaseTop { 21 | public UserGiven(GuildRepository guildRepository, Configuration configuration) { 22 | super(guildRepository, configuration); 23 | } 24 | 25 | @Override 26 | protected Ranking buildRanking(SlashCommandInteractionEvent event, RepGuild guild, ReputationMode reputationMode, int pageSize) { 27 | Member user = Optional.ofNullable(event.getOption("user")).map(OptionMapping::getAsMember).orElse(event.getMember()); 28 | return guild.reputation().ranking().user().given().byMode(reputationMode, pageSize, user); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/actions/user/received/UserReceived.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.actions.user.received; 7 | 8 | import de.chojo.jdautil.interactions.user.User; 9 | import de.chojo.jdautil.interactions.user.provider.UserProvider; 10 | import de.chojo.repbot.actions.user.received.handler.ReceivedReputation; 11 | import de.chojo.repbot.config.Configuration; 12 | import de.chojo.repbot.dao.provider.GuildRepository; 13 | import net.dv8tion.jda.api.Permission; 14 | import net.dv8tion.jda.api.interactions.InteractionContextType; 15 | 16 | import java.util.Set; 17 | 18 | public class UserReceived implements UserProvider { 19 | private final GuildRepository guildRepository; 20 | private final Configuration configuration; 21 | 22 | public UserReceived(GuildRepository guildRepository, Configuration configuration) { 23 | this.guildRepository = guildRepository; 24 | this.configuration = configuration; 25 | } 26 | 27 | @Override 28 | public User user() { 29 | return User.of("Received Reputation") 30 | .handler(new ReceivedReputation(guildRepository, configuration)) 31 | .setContext(Set.of(InteractionContextType.GUILD)) 32 | .withPermission(Permission.MESSAGE_MANAGE) 33 | .build(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/supporter/handler/BaseSupporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.supporter.handler; 7 | 8 | import de.chojo.repbot.config.Configuration; 9 | import de.chojo.repbot.config.elements.sku.Subscription; 10 | import net.dv8tion.jda.api.entities.Entitlement; 11 | 12 | public class BaseSupporter { 13 | protected final Configuration configuration; 14 | 15 | public BaseSupporter(Configuration configuration) { 16 | this.configuration = configuration; 17 | } 18 | 19 | protected boolean isLifetimeSku(Entitlement entitlement) { 20 | return configuration.skus().subscriptions().stream().anyMatch(sub -> entitlement.getSkuIdLong() == sub.lifetimeSku()); 21 | } 22 | 23 | protected Subscription getSubscription(Entitlement entitlement) { 24 | return configuration.skus().subscriptions().stream() 25 | .filter(sub -> entitlement.getSkuIdLong() == sub.lifetimeSku()) 26 | .findFirst() 27 | .orElseThrow(() -> new IllegalArgumentException("No subscription found for entitlement " + entitlement.getSkuIdLong())); 28 | } 29 | 30 | protected boolean isAvailable(Entitlement entitlement) { 31 | return !entitlement.isConsumed() && !entitlement.isDeleted(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/ranking/handler/user/UserReceived.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.ranking.handler.user; 7 | 8 | import de.chojo.repbot.commands.ranking.handler.BaseTop; 9 | import de.chojo.repbot.config.Configuration; 10 | import de.chojo.repbot.dao.access.guild.RepGuild; 11 | import de.chojo.repbot.dao.access.guild.settings.sub.ReputationMode; 12 | import de.chojo.repbot.dao.pagination.Ranking; 13 | import de.chojo.repbot.dao.provider.GuildRepository; 14 | import net.dv8tion.jda.api.entities.Member; 15 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 16 | import net.dv8tion.jda.api.interactions.commands.OptionMapping; 17 | 18 | import java.util.Optional; 19 | 20 | public class UserReceived extends BaseTop { 21 | public UserReceived(GuildRepository guildRepository, Configuration configuration) { 22 | super(guildRepository, configuration); 23 | } 24 | 25 | @Override 26 | protected Ranking buildRanking(SlashCommandInteractionEvent event, RepGuild guild, ReputationMode reputationMode, int pageSize) { 27 | Member user = Optional.ofNullable(event.getOption("user")).map(OptionMapping::getAsMember).orElse(event.getMember()); 28 | return guild.reputation().ranking().user().received().byMode(reputationMode, pageSize, user); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/announcement/AnnouncementState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.announcement; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | import net.dv8tion.jda.api.interactions.commands.OptionMapping; 13 | 14 | public class AnnouncementState implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | 17 | public AnnouncementState(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | var announcements = guildRepository.guild(event.getGuild()).settings().announcements(); 24 | if (announcements.active(event.getOption("active", OptionMapping::getAsBoolean))) { 25 | event.reply(context.localize("command.channel.announcement.state.message.active")).complete(); 26 | } else { 27 | event.reply(context.localize("command.channel.announcement.state.message.inactive")).complete(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/prune/Prune.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.prune; 7 | 8 | import de.chojo.jdautil.interactions.slash.Argument; 9 | import de.chojo.jdautil.interactions.slash.Slash; 10 | import de.chojo.jdautil.interactions.slash.SubCommand; 11 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 12 | import de.chojo.repbot.commands.prune.handler.Guild; 13 | import de.chojo.repbot.commands.prune.handler.User; 14 | import de.chojo.repbot.service.GdprService; 15 | import net.dv8tion.jda.api.Permission; 16 | 17 | public class Prune extends SlashCommand { 18 | 19 | public Prune(GdprService service) { 20 | super(Slash.of("prune", "command.prune.description") 21 | .guildOnly() 22 | .withPermission(Permission.MESSAGE_MANAGE) 23 | .subCommand(SubCommand.of("user", "command.prune.user.description") 24 | .handler(new User(service)) 25 | .argument(Argument.user("user", "command.prune.user.options.user.description")) 26 | .argument(Argument.text("userid", "command.prune.user.options.userid.description"))) 27 | .subCommand(SubCommand.of("guild", "command.prune.guild.description") 28 | .handler(new Guild(service))) 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/de/chojo/repbot/TestScratch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot; 7 | 8 | 9 | import de.chojo.repbot.core.Threading; 10 | import org.junit.jupiter.api.Disabled; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.concurrent.TimeUnit; 16 | import java.util.regex.Pattern; 17 | import java.util.stream.Stream; 18 | 19 | public class TestScratch { 20 | @Test 21 | @Disabled 22 | void threadingException() throws InterruptedException { 23 | Threading threading = new Threading(); 24 | 25 | threading.repBotWorker().submit(() ->{ 26 | throw new RuntimeException(); 27 | }); 28 | 29 | threading.repBotWorker().schedule(() ->{ 30 | throw new RuntimeException(); 31 | }, 10, TimeUnit.SECONDS); 32 | 33 | Thread.sleep(15000); 34 | 35 | threading.repBotWorker().shutdown(); 36 | } 37 | 38 | @Test 39 | void illegalRegex(){ 40 | Pattern.compile("(?i)(?(?:^|\\b)thanks(?:$|\\b)|(?:^|\\b)vouch(?:$|\\b)|(?:^|\\b)<\\#1071818688220639353>(?:$|\\b)|(?:^|\\b)trustpilot(?:$|\\b)|(?:^|\\b)voucher(?:$|\\b)|(?:^|\\b)vouched(?:$|\\b)|(?:^|\\b)google(?:$|\\b))", 41 | Pattern.CASE_INSENSITIVE + Pattern.MULTILINE + Pattern.DOTALL + Pattern.COMMENTS); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/system/Restart.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.system; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.config.Configuration; 11 | import de.chojo.repbot.util.LogNotify; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | import org.slf4j.Logger; 14 | 15 | import static org.slf4j.LoggerFactory.getLogger; 16 | 17 | public class Restart implements SlashHandler { 18 | private static final Logger log = getLogger(Restart.class); 19 | private final Configuration configuration; 20 | 21 | public Restart(Configuration configuration) { 22 | this.configuration = configuration; 23 | } 24 | 25 | @Override 26 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 27 | if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { 28 | event.reply("No.").setEphemeral(true).complete(); 29 | return; 30 | } 31 | log.info(LogNotify.STATUS, "Restart command received from {}. Attempting restart.", event.getUser().getAsTag()); 32 | event.reply("Restarting. Will be back soon!").complete(); 33 | System.exit(10); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/system/Shudown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.system; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.config.Configuration; 11 | import de.chojo.repbot.util.LogNotify; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | import org.slf4j.Logger; 14 | 15 | import static org.slf4j.LoggerFactory.getLogger; 16 | 17 | public class Shudown implements SlashHandler { 18 | private static final Logger log = getLogger(Shudown.class); 19 | private final Configuration configuration; 20 | 21 | public Shudown(Configuration configuration) { 22 | this.configuration = configuration; 23 | } 24 | 25 | @Override 26 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 27 | if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { 28 | event.reply("No.").setEphemeral(true).complete(); 29 | return; 30 | } 31 | log.info(LogNotify.STATUS, "Shutdown command received from {}. Shutting down.", event.getUser().getAsTag()); 32 | event.reply("Initializing shutdown. Good bye :c").complete(); 33 | System.exit(0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/system/Upgrade.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.system; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.config.Configuration; 11 | import de.chojo.repbot.util.LogNotify; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | import org.slf4j.Logger; 14 | 15 | import static org.slf4j.LoggerFactory.getLogger; 16 | 17 | public class Upgrade implements SlashHandler { 18 | private static final Logger log = getLogger(Upgrade.class); 19 | private final Configuration configuration; 20 | 21 | public Upgrade(Configuration configuration) { 22 | this.configuration = configuration; 23 | } 24 | 25 | @Override 26 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 27 | if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { 28 | event.reply("No.").setEphemeral(true).complete(); 29 | return; 30 | } 31 | log.info(LogNotify.STATUS, "Upgrade command received from {}. Attempting upgrade.", event.getUser().getAsTag()); 32 | event.reply("Starting upgrade. Will be back soon!").complete(); 33 | System.exit(20); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/autopost/AutopostRefresh.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.autopost; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import de.chojo.repbot.service.AutopostService; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class AutopostRefresh implements SlashHandler { 15 | private final AutopostService autopostService; 16 | private final GuildRepository guildRepository; 17 | 18 | public AutopostRefresh(AutopostService autopostService, GuildRepository guildRepository) { 19 | this.autopostService = autopostService; 20 | this.guildRepository = guildRepository; 21 | } 22 | 23 | @Override 24 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 25 | if (!guildRepository.guild(event.getGuild()).settings().autopost().active()) { 26 | event.reply("command.channel.autopost.refresh.message.inactive").setEphemeral(true).queue(); 27 | return; 28 | } 29 | autopostService.update(event.getGuild()); 30 | event.reply("command.channel.autopost.refresh.message.refreshed").setEphemeral(true).queue(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/gdpr/handler/Request.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.gdpr.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.access.Gdpr; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | 13 | public class Request implements SlashHandler { 14 | private final Gdpr gdpr; 15 | 16 | public Request(Gdpr gdpr) { 17 | this.gdpr = gdpr; 18 | } 19 | 20 | @Override 21 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 22 | event.deferReply(true).complete(); 23 | var user = gdpr.request(event.getUser()); 24 | var request = user.request(); 25 | if (request) { 26 | if (user.sendData()) { 27 | user.requestSend(); 28 | event.getHook().editOriginal(context.localize("command.gdpr.request.message.send")).complete(); 29 | } else { 30 | user.requestSendFailed(); 31 | event.getHook().editOriginal(context.localize("command.gdpr.request.message.failed")).complete(); 32 | } 33 | } else { 34 | event.getHook().editOriginal(context.localize("command.gdpr.request.message.requested")).complete(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/bot/handler/entitlement/Show.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.bot.handler.entitlement; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import net.dv8tion.jda.api.entities.Entitlement; 11 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 12 | import net.dv8tion.jda.api.interactions.commands.OptionMapping; 13 | 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | 17 | public class Show implements SlashHandler { 18 | @Override 19 | public void onSlashCommand(SlashCommandInteractionEvent slash, EventContext eventContext) { 20 | Long guildId = slash.getOption("guild_id", OptionMapping::getAsLong); 21 | if (guildId == null) { 22 | guildId = slash.getGuild().getIdLong(); 23 | } 24 | 25 | List complete = slash.getJDA().retrieveEntitlements().guild(guildId).excludeEnded(true).complete(); 26 | String collect = complete.stream() 27 | .map(ent -> "SKU: %s\nType: %s\nTill: %s (Consumed: %s)\nEntitlement Id: %s".formatted(ent.getSkuId(), ent.getType(), ent.getTimeEnding(), ent.isConsumed(), ent.getId())) 28 | .collect(Collectors.joining()); 29 | slash.reply(collect).complete(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/core/Shutdown.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.core; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.slf4j.Logger; 10 | 11 | import static org.slf4j.LoggerFactory.getLogger; 12 | 13 | public class Shutdown { 14 | private static final Logger log = getLogger(Shutdown.class); 15 | private final Bot bot; 16 | private final Threading threading; 17 | private final Data data; 18 | 19 | private Shutdown(Bot bot, Threading threading, Data data) { 20 | this.bot = bot; 21 | this.threading = threading; 22 | this.data = data; 23 | } 24 | 25 | public static Shutdown create(Bot bot, Threading threading, Data data) { 26 | var shutdown = new Shutdown(bot, threading, data); 27 | shutdown.init(); 28 | return shutdown; 29 | } 30 | 31 | public void init() { 32 | log.info("Creating Shutdown Hook"); 33 | var shutdown = new Thread(() -> { 34 | log.info("Shuting down shardmanager."); 35 | bot.shutdown(); 36 | log.info("Shutting down scheduler."); 37 | threading.shutdown(); 38 | log.info("Shutting down database connections."); 39 | data.shutDown(); 40 | log.info("Bot shutdown complete."); 41 | LogManager.shutdown(); 42 | }); 43 | Runtime.getRuntime().addShutdownHook(shutdown); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/locale/Locale.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.locale; 7 | 8 | import de.chojo.jdautil.interactions.slash.Argument; 9 | import de.chojo.jdautil.interactions.slash.Slash; 10 | import de.chojo.jdautil.interactions.slash.SubCommand; 11 | import de.chojo.jdautil.interactions.slash.provider.SlashCommand; 12 | import de.chojo.repbot.commands.locale.handler.List; 13 | import de.chojo.repbot.commands.locale.handler.Reset; 14 | import de.chojo.repbot.commands.locale.handler.Set; 15 | import de.chojo.repbot.dao.provider.GuildRepository; 16 | 17 | public class Locale extends SlashCommand { 18 | public Locale(GuildRepository guildRepository) { 19 | super(Slash.of("locale", "command.locale.description") 20 | .guildOnly() 21 | .adminCommand() 22 | .subCommand(SubCommand.of("set", "command.locale.set.description") 23 | .handler(new Set(guildRepository)) 24 | .argument(Argument.text("language", "command.locale.set.options.language.description").asRequired() 25 | .withAutoComplete())) 26 | .subCommand(SubCommand.of("reset", "command.locale.reset.description") 27 | .handler(new Reset(guildRepository))) 28 | .subCommand(SubCommand.of("list", "command.locale.list.description") 29 | .handler(new List())) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/thankwords/handler/List.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.thankwords.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.wrapper.EventContext; 10 | import de.chojo.repbot.dao.provider.GuildRepository; 11 | import net.dv8tion.jda.api.entities.Guild; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | import org.apache.commons.lang3.StringUtils; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.stream.Collectors; 17 | 18 | public class List implements SlashHandler { 19 | private final GuildRepository guildRepository; 20 | 21 | public List(GuildRepository guildRepository) { 22 | this.guildRepository = guildRepository; 23 | } 24 | 25 | @Override 26 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 27 | var pattern = getGuildPattern(event.getGuild()); 28 | if (pattern == null) return; 29 | 30 | event.reply(context.localize("command.thankwords.list.message.list") + "\n" + pattern).complete(); 31 | } 32 | 33 | @Nullable 34 | private String getGuildPattern(Guild guild) { 35 | return guildRepository.guild(guild).settings().thanking().thankwords().words().stream() 36 | .map(w -> StringUtils.wrap(w, "`")) 37 | .collect(Collectors.joining(", ")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/reputation/SubmitResultType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service.reputation; 7 | 8 | public enum SubmitResultType { 9 | NO_DONOR_ROLE("submitresult.nodonorrole"), 10 | CHANNEL_INACTIVE("submitresult.channelinactive"), 11 | NO_TARGETS("submitresult.notargets"), 12 | NO_RECENT_MEMBERS("submitresult.norecentmembers"), 13 | // TODO: Switch to old locale key after a few days (10.08.2025) 14 | COOLDOWN_ACTIVE("submitresult.cooldownactive"), 15 | COOLDOWN_ONCE("submitresult.cooldownonce"), 16 | EMBED_SEND("submitresult.embedsend"), 17 | DONOR_LIMIT("submitresult.donorlimit"), 18 | NO_RECEIVER_ROLE("submitresult.noreceiverrole"), 19 | THANK_TYPE_DISABLED("submitresult.thanktypedisabled"), 20 | SELF_VOTE("submitresult.selfvote"), 21 | TARGET_NOT_IN_CONTEXT("submitresult.targetnotincontext"), 22 | DONOR_NOT_IN_CONTEXT("submitresult.donornotincontext"), 23 | OUTDATED_REFERENCE_MESSAGE("submitresult.outdatedreferencemessage"), 24 | OUTDATED_MESSAGE("submitresult.outdatedmessage"), 25 | RECEIVER_LIMIT("submitresult.receiverlimit"), 26 | ALREADY_PRESENT("submitresult.alreadypresent"), 27 | SUBMITTING("submitresult.submitting"), 28 | ALL_COOLDOWN("submitresult.allcooldown"); 29 | 30 | private final String localeKey; 31 | 32 | SubmitResultType(String localeKey) { 33 | this.localeKey = localeKey; 34 | } 35 | 36 | public String localeKey() { 37 | return localeKey; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/invite/handler/Show.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.invite.handler; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; 10 | import de.chojo.jdautil.localization.util.Replacement; 11 | import de.chojo.jdautil.wrapper.EventContext; 12 | import de.chojo.repbot.config.Configuration; 13 | import net.dv8tion.jda.api.entities.MessageEmbed; 14 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | public class Show implements SlashHandler { 18 | private final Configuration configuration; 19 | 20 | public Show(Configuration configuration) { 21 | this.configuration = configuration; 22 | } 23 | 24 | @Override 25 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 26 | event.replyEmbeds(getResponse(context)).complete(); 27 | } 28 | 29 | @NotNull 30 | private MessageEmbed getResponse(EventContext context) { 31 | return new LocalizedEmbedBuilder(context.guildLocalizer()) 32 | .setTitle("command.invite.message.title") 33 | .setDescription("command.invite.message.click", Replacement.create("URL", configuration.links() 34 | .invite())) 35 | .build(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/ReputationBot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot; 7 | 8 | import de.chojo.repbot.config.Configuration; 9 | import de.chojo.repbot.core.Bot; 10 | import de.chojo.repbot.core.Data; 11 | import de.chojo.repbot.core.Localization; 12 | import de.chojo.repbot.core.Shutdown; 13 | import de.chojo.repbot.core.Threading; 14 | import de.chojo.repbot.core.Web; 15 | 16 | import javax.security.auth.login.LoginException; 17 | import java.io.IOException; 18 | import java.sql.SQLException; 19 | 20 | public class ReputationBot { 21 | private static ReputationBot instance; 22 | 23 | public static void main(String[] args) throws SQLException, IOException, LoginException { 24 | ReputationBot.instance = new ReputationBot(); 25 | instance.start(); 26 | } 27 | 28 | /** 29 | * Starts the bot. 30 | * 31 | * @throws SQLException If the database connection fails. 32 | * @throws IOException If the configuration file fails to load. 33 | */ 34 | private void start() throws SQLException, IOException, LoginException { 35 | var configuration = Configuration.create(); 36 | 37 | var threading = new Threading(); 38 | 39 | var data = Data.create(threading, configuration); 40 | 41 | var localization = Localization.create(data, configuration); 42 | 43 | var bot = Bot.create(data, threading, configuration, localization); 44 | 45 | Shutdown.create(bot, threading, data); 46 | 47 | Web.create(bot, data, threading, configuration); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/provider/Metrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.provider; 7 | 8 | import de.chojo.repbot.dao.access.metrics.Commands; 9 | import de.chojo.repbot.dao.access.metrics.Messages; 10 | import de.chojo.repbot.dao.access.metrics.Reputation; 11 | import de.chojo.repbot.dao.access.metrics.Service; 12 | import de.chojo.repbot.dao.access.metrics.Statistic; 13 | import de.chojo.repbot.dao.access.metrics.Users; 14 | 15 | import javax.sql.DataSource; 16 | 17 | public class Metrics { 18 | private final Commands commands; 19 | private final Messages messages; 20 | private final Users users; 21 | private final Statistic statistic; 22 | private final Reputation reputation; 23 | private final Service service; 24 | 25 | public Metrics(DataSource dataSource) { 26 | commands = new Commands(); 27 | messages = new Messages(); 28 | users = new Users(); 29 | statistic = new Statistic(); 30 | reputation = new Reputation(); 31 | service = new Service(); 32 | } 33 | 34 | public Commands commands() { 35 | return commands; 36 | } 37 | 38 | public Messages messages() { 39 | return messages; 40 | } 41 | 42 | public Users users() { 43 | return users; 44 | } 45 | 46 | public Statistic statistic() { 47 | return statistic; 48 | } 49 | 50 | public Reputation reputation() { 51 | return reputation; 52 | } 53 | 54 | public Service service() { 55 | return service; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/MonitorService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service; 7 | 8 | import de.chojo.repbot.core.Data; 9 | import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent; 10 | import net.dv8tion.jda.api.hooks.ListenerAdapter; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.slf4j.Logger; 13 | 14 | import java.util.concurrent.Executors; 15 | import java.util.concurrent.ScheduledExecutorService; 16 | 17 | import static org.slf4j.LoggerFactory.getLogger; 18 | 19 | public class MonitorService extends ListenerAdapter { 20 | private final Data data; 21 | private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 22 | private static final Logger log = getLogger(MonitorService.class); 23 | 24 | public MonitorService(Data data) { 25 | this.data = data; 26 | } 27 | 28 | @Override 29 | public void onGenericInteractionCreate(@NotNull GenericInteractionCreateEvent event) { 30 | data.metrics().service().countInteraction(); 31 | executorService.schedule(() -> check(event), 10, java.util.concurrent.TimeUnit.SECONDS); 32 | } 33 | 34 | private void check(GenericInteractionCreateEvent event) { 35 | if (event.isAcknowledged()) { 36 | data.metrics().service().successfulInteraction(); 37 | return; 38 | } 39 | data.metrics().service().failedInteraction(); 40 | log.error("Interaction not acknowledged after 10 seconds. {}", event); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/service/MetricService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.service; 7 | 8 | import de.chojo.repbot.dao.provider.Metrics; 9 | 10 | import java.time.DayOfWeek; 11 | import java.time.ZoneOffset; 12 | import java.time.ZonedDateTime; 13 | import java.time.temporal.ChronoUnit; 14 | import java.util.concurrent.ScheduledExecutorService; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | public class MetricService implements Runnable { 18 | private final Metrics metrics; 19 | 20 | public MetricService(Metrics metrics) { 21 | this.metrics = metrics; 22 | } 23 | 24 | public static MetricService create(ScheduledExecutorService executorService, Metrics metrics) { 25 | var now = ZonedDateTime.now(ZoneOffset.UTC); 26 | var base = now.toLocalDate().atStartOfDay().plus(1, ChronoUnit.DAYS).plus(1, ChronoUnit.HOURS) 27 | .atOffset(ZoneOffset.UTC); 28 | var minutes = now.until(base, ChronoUnit.MINUTES); 29 | var service = new MetricService(metrics); 30 | executorService.scheduleAtFixedRate(service, minutes, 1440, TimeUnit.MINUTES); 31 | return service; 32 | } 33 | 34 | @Override 35 | public void run() { 36 | metrics.reputation().saveRepCounts(); 37 | if (ZonedDateTime.now().getDayOfMonth() == 1) { 38 | metrics.users().saveUserCountMonth(); 39 | } 40 | if (ZonedDateTime.now().getDayOfWeek() == DayOfWeek.MONDAY) { 41 | metrics.users().saveUserCountWeek(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/config/exception/ConfigurationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.config.exception; 7 | 8 | public class ConfigurationException extends RuntimeException { 9 | /** 10 | * Constructs a new runtime exception with the specified detail message. 11 | * The cause is not initialized, and may subsequently be initialized by a 12 | * call to {@link #initCause}. 13 | * 14 | * @param message the detail message. The detail message is saved for 15 | * later retrieval by the {@link #getMessage()} method. 16 | */ 17 | public ConfigurationException(String message) { 18 | super(message); 19 | } 20 | 21 | /** 22 | * Constructs a new runtime exception with the specified detail message and 23 | * cause.

Note that the detail message associated with 24 | * {@code cause} is not automatically incorporated in 25 | * this runtime exception's detail message. 26 | * 27 | * @param message the detail message (which is saved for later retrieval 28 | * by the {@link #getMessage()} method). 29 | * @param cause the cause (which is saved for later retrieval by the 30 | * {@link #getCause()} method). (A {@code null} value is 31 | * permitted, and indicates that the cause is nonexistent or 32 | * unknown.) 33 | * @since 1.4 34 | */ 35 | public ConfigurationException(String message, Throwable cause) { 36 | super(message, cause); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageAge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.abuseprotection.handler.message; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 13 | 14 | public class MaxMessageAge implements SlashHandler { 15 | private final GuildRepository guildRepository; 16 | 17 | public MaxMessageAge(GuildRepository guildRepository) { 18 | this.guildRepository = guildRepository; 19 | } 20 | 21 | @Override 22 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 23 | var guild = guildRepository.guild(event.getGuild()); 24 | var abuseSettings = guild.settings().abuseProtection(); 25 | if (event.getOptions().isEmpty()) { 26 | event.reply(context.localize("command.abuseprotection.message.age.message.get", 27 | Replacement.create("MINUTES", abuseSettings.maxMessageAge()))).queue(); 28 | return; 29 | } 30 | var age = event.getOption("minutes").getAsInt(); 31 | 32 | age = Math.max(0, age); 33 | event.reply(context.localize("command.abuseprotection.message.age.message.get", 34 | Replacement.create("MINUTES", abuseSettings.maxMessageAge(age)))).queue(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/announcement/AnnouncementLocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.announcement; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.entities.channel.ChannelType; 13 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 14 | 15 | public class AnnouncementLocation implements SlashHandler { 16 | private final GuildRepository guildRepository; 17 | 18 | public AnnouncementLocation(GuildRepository guildRepository) { 19 | this.guildRepository = guildRepository; 20 | } 21 | 22 | @Override 23 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 24 | var announcements = guildRepository.guild(event.getGuild()).settings().announcements(); 25 | var channel = event.getOption("channel"); 26 | if (channel.getChannelType() != ChannelType.TEXT) { 27 | event.reply(context.localize("error.onlyTextChannel")).setEphemeral(true).complete(); 28 | return; 29 | } 30 | 31 | announcements.channel(channel.getAsChannel().asTextChannel()); 32 | event.reply(context.localize("command.channel.announcement.channel.message.set", 33 | Replacement.createMention(channel.getAsChannel().asTextChannel()))).complete(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/MatchResultSnapshot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.dao.snapshots.analyzer.match; 7 | 8 | import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; 9 | import de.chojo.jdautil.util.Colors; 10 | import de.chojo.repbot.analyzer.results.match.ThankType; 11 | import de.chojo.repbot.dao.snapshots.analyzer.ResultSnapshot; 12 | import de.chojo.repbot.dao.snapshots.ResultEntry; 13 | import net.dv8tion.jda.api.entities.Guild; 14 | import net.dv8tion.jda.api.entities.User; 15 | 16 | public abstract class MatchResultSnapshot implements ResultSnapshot { 17 | private final ThankType thankType; 18 | private final long donorId; 19 | private final String match; 20 | 21 | public MatchResultSnapshot(ThankType thankType, long donorId, String match) { 22 | this.thankType = thankType; 23 | this.donorId = donorId; 24 | this.match = match; 25 | } 26 | 27 | public ThankType thankType() { 28 | return thankType; 29 | } 30 | 31 | public long donorId() { 32 | return donorId; 33 | } 34 | 35 | public String match() { 36 | return match; 37 | } 38 | 39 | @Override 40 | public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { 41 | builder.setTitle(thankType.nameLocaleKey()) 42 | .setColor(Colors.Pastel.DARK_GREEN) 43 | .addField("command.log.analyzer.message.field.matchedWord", match, true) 44 | .addField("words.donor", User.fromId(donorId).getAsMention(), true); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /docs/metrics.md: -------------------------------------------------------------------------------- 1 | # Metrics 2 | 3 | You are curious about the traffic and usage of the bot? 4 | 5 | We are as well! That's why we compiled some nice graphs on this page. These are showing nearly realtime data directly 6 | from the bot. The graphs are refreshed automatically. 7 | 8 | Most of the graphs show data with an offset of one week or month. That avoids showing dirty or incomplete data. If you 9 | want more insights you can try out our [API](https://repbot.chojo.de/docs). 10 | 11 | ## Reputation 12 | 13 | ![](https://repbot.chojo.de/v1/metrics/reputation/count/month/1/24) 14 | 15 | ![](https://repbot.chojo.de/v1/metrics/reputation/total/month/0/24) 16 | 17 | ![](https://repbot.chojo.de/v1/metrics/reputation/dow/month/1) 18 | 19 | ![](https://repbot.chojo.de/v1/metrics/reputation/type/total/month/0/48) 20 | 21 | ![](https://repbot.chojo.de/v1/metrics/reputation/type/count/month/0/48) 22 | 23 | ![](https://repbot.chojo.de/v1/metrics/reputation/changes/week/0/52) 24 | 25 | ## Commands 26 | 27 | ![](https://repbot.chojo.de/v1/metrics/commands/count/week/1/52) 28 | 29 | ![](https://repbot.chojo.de/v1/metrics/commands/usage/week/1) 30 | 31 | ![](https://repbot.chojo.de/v1/metrics/commands/usage/month/1) 32 | 33 | ## Messages 34 | 35 | ![](https://repbot.chojo.de/v1/metrics/messages/count/week/1/52) 36 | 37 | ![](https://repbot.chojo.de/v1/metrics/messages/total/week/0/52) 38 | 39 | ## Users 40 | 41 | ![](https://repbot.chojo.de/v1/metrics/users/active/week/1/52) 42 | 43 | ![](https://repbot.chojo.de/v1/metrics/users/active/month/1/24) 44 | 45 | ## Service 46 | 47 | ![](https://repbot.chojo.de/v1/metrics/service/count/hour/0/120) 48 | 49 | ![](https://repbot.chojo.de/v1/metrics/service/count/week/0/104) 50 | -------------------------------------------------------------------------------- /src/main/java/de/chojo/repbot/commands/channel/handler/systemchannel/SystemChannelEnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: AGPL-3.0-only 3 | * 4 | * Copyright (C) RainbowDashLabs and Contributor 5 | */ 6 | package de.chojo.repbot.commands.channel.handler.systemchannel; 7 | 8 | import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; 9 | import de.chojo.jdautil.localization.util.Replacement; 10 | import de.chojo.jdautil.wrapper.EventContext; 11 | import de.chojo.repbot.dao.provider.GuildRepository; 12 | import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; 13 | import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; 14 | 15 | import static net.dv8tion.jda.api.entities.channel.ChannelType.TEXT; 16 | 17 | public class SystemChannelEnable implements SlashHandler { 18 | private final GuildRepository guildRepository; 19 | 20 | public SystemChannelEnable(GuildRepository guildRepository) { 21 | this.guildRepository = guildRepository; 22 | } 23 | 24 | @Override 25 | public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { 26 | GuildChannelUnion channel = event.getOption("channel").getAsChannel(); 27 | 28 | if(channel.getType() != TEXT){ 29 | event.reply(context.localize("error.onlyTextChannel")).setEphemeral(true).queue(); 30 | return; 31 | } 32 | 33 | guildRepository.guild(event.getGuild()).settings().general().systemChannel(channel.getIdLong()); 34 | event.reply(context.localize("command.channel.systemchannel.enable.message.enabled", Replacement.create("CHANNEL",channel.getAsMention()))).setEphemeral(true).queue(); 35 | } 36 | } 37 | --------------------------------------------------------------------------------