Add settings slash command and rework several things to fit it better

Deprecate several things
This commit is contained in:
NovaFox161
2021-08-10 12:04:04 -05:00
parent 9a70ac37cc
commit 7cc2367ed9
32 changed files with 732 additions and 581 deletions

View File

@@ -11,6 +11,7 @@ import discord4j.rest.util.Image;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.dreamexposure.discal.client.DisCalClient;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.enums.announcement.AnnouncementStyle;
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType;
import org.dreamexposure.discal.core.enums.event.EventColor;
import org.dreamexposure.discal.core.object.BotSettings;
@@ -287,7 +288,7 @@ public class AnnouncementMessageFormatter {
embed.color(GlobalVal.getDiscalColor());
}
if (!settings.getSimpleAnnouncements()) {
if (settings.getAnnouncementStyle() == AnnouncementStyle.FULL) {
embed.footer(Messages.getMessage("Embed.Announcement.Announce.ID", "%id%",
a.getAnnouncementId().toString(), settings), null);
}
@@ -313,7 +314,7 @@ public class AnnouncementMessageFormatter {
}
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Description", settings), description, true);
}
if (!settings.getSimpleAnnouncements()) {
if (settings.getAnnouncementStyle() == AnnouncementStyle.FULL) {
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Date", settings), sDate, true);
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Time", settings), sTime, true);
embed.addField(Messages.getMessage("Embed.Announcement.Announce.TimeZone", settings), tz, true);
@@ -331,7 +332,7 @@ public class AnnouncementMessageFormatter {
}
}
if (!settings.getSimpleAnnouncements())
if (settings.getAnnouncementStyle() == AnnouncementStyle.FULL)
embed.addField(Messages.getMessage("Embed.Announcement.Announce.EventID", settings), event.getId(), false);
if (!"None".equalsIgnoreCase(a.getInfo()) && !"".equalsIgnoreCase(a.getInfo()))
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Info", settings), a.getInfo(), false);

View File

@@ -8,6 +8,7 @@ import discord4j.rest.util.Image;
import org.dreamexposure.discal.client.DisCalClient;
import org.dreamexposure.discal.core.database.DatabaseManager;
import org.dreamexposure.discal.core.enums.event.EventColor;
import org.dreamexposure.discal.core.enums.time.TimeFormat;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.GuildSettings;
import org.dreamexposure.discal.core.object.event.EventCreatorResponse;
@@ -282,8 +283,10 @@ public class EventMessageFormatter {
}
).map(ZoneId::of).map(tz -> {
DateTimeFormatter format;
if (settings.getTwelveHour()) format = DateTimeFormatter.ofPattern("hh:mm:ss a").withZone(tz);
else format = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(tz);
if (settings.getTimeFormat() == TimeFormat.TWELVE_HOUR)
format = DateTimeFormatter.ofPattern("hh:mm:ss a").withZone(tz);
else
format = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(tz);
if (eventDateTime.getDateTime() != null) { //Date with time
return format.format(Instant.ofEpochMilli(eventDateTime.getDateTime().getValue()));

View File

@@ -13,7 +13,6 @@ import org.dreamexposure.discal.core.object.command.CommandInfo;
import org.dreamexposure.discal.core.utils.ChannelUtils;
import org.dreamexposure.discal.core.utils.GlobalVal;
import org.dreamexposure.discal.core.utils.PermissionChecker;
import org.dreamexposure.discal.core.utils.RoleUtils;
import reactor.core.publisher.Mono;
import reactor.function.TupleUtils;
@@ -94,17 +93,11 @@ public class DisCalCommand implements Command {
} else {
return switch (args[0].toLowerCase()) {
case "discal" -> this.moduleDisCalInfo(event, settings);
case "settings" -> this.moduleSettings(event, settings);
case "role" -> this.moduleControlRole(args, event, settings);
case "channel" -> this.moduleDisCalChannel(args, event, settings);
case "simpleannouncement" -> this.moduleSimpleAnnouncement(event, settings);
case "dmannouncement", "dmannouncements" -> this.moduleDmAnnouncements(event, settings);
case "language", "lang" -> this.moduleLanguage(args, event, settings);
case "prefix" -> this.modulePrefix(args, event, settings);
case "invite" -> this.moduleInvite(event, settings);
case "dashboard" -> this.moduleDashboard(event, settings);
case "brand" -> this.moduleBrand(event, settings);
case "timeformat", "twelvehour" -> this.moduleTwelveHour(event, settings);
default -> Messages.sendMessage(Messages.getMessage("Notification.Args.Invalid", settings), event);
};
}
@@ -144,32 +137,6 @@ public class DisCalCommand implements Command {
return embedMono.flatMap(embed -> Messages.sendMessage(embed, event)).then();
}
private Mono<Void> moduleControlRole(final String[] args, final MessageCreateEvent event, final GuildSettings settings) {
return PermissionChecker.hasManageServerRole(event)
.filter(identity -> identity)
.flatMap(ignore -> {
if (args.length == 2) {
final String roleName = args[1];
if ("everyone".equalsIgnoreCase(roleName)) {
settings.setControlRole("everyone");
return DatabaseManager.INSTANCE.updateSettings(settings)
.then(Messages.sendMessage(Messages.getMessage("DisCal.ControlRole.Reset", settings), event));
} else {
return event.getGuild().flatMap(g -> RoleUtils.getRole(roleName, g)
.doOnNext(r -> settings.setControlRole(r.getId().asString()))
.flatMap(r ->
DatabaseManager.INSTANCE.updateSettings(settings)
.then(Messages.sendMessage(Messages.getMessage("DisCal.ControlRole.Set", "%role%",
r.getName(), settings), event))
).switchIfEmpty(Messages.sendMessage(Messages.getMessage("DisCal.ControlRole.Invalid", settings), event))
);
}
} else {
return Messages.sendMessage(Messages.getMessage("DisCal.ControlRole.Specify", settings), event);
}
}).switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings), event))
.then();
}
private Mono<Void> moduleDisCalChannel(final String[] args, final MessageCreateEvent event, final GuildSettings settings) {
return PermissionChecker.hasManageServerRole(event)
@@ -198,55 +165,6 @@ public class DisCalCommand implements Command {
.then();
}
private Mono<Void> moduleSimpleAnnouncement(final MessageCreateEvent event, final GuildSettings settings) {
return Mono.just(settings)
.doOnNext(s -> s.setSimpleAnnouncements(!s.getSimpleAnnouncements()))
.flatMap(DatabaseManager.INSTANCE::updateSettings)
.then(Messages.sendMessage(
Messages.getMessage("DisCal.SimpleAnnouncement", "%value%", settings.getSimpleAnnouncements() + "", settings)
, event))
.then();
}
private Mono<Void> moduleSettings(final MessageCreateEvent event, final GuildSettings settings) {
final Mono<Guild> guildMono = event.getGuild().cache();
final Mono<String> dRoleMono = RoleUtils.getRoleNameFromID(settings.getControlRole(), event).defaultIfEmpty("everyone");
final Mono<String> dChanMono = guildMono.flatMap(g ->
ChannelUtils.getChannelNameFromNameOrId(settings.getDiscalChannel(), g)).defaultIfEmpty("All Channels");
final Mono<EmbedCreateSpec> embedMono = Mono.zip(guildMono, dRoleMono, dChanMono)
.map(TupleUtils.function((guild, dRole, dChannel) -> {
var builder = EmbedCreateSpec.builder()
.title(Messages.getMessage("Embed.DisCal.Settings.Title", settings))
.addField(Messages.getMessage("Embed.Discal.Settings.Role", settings), dRole, true)
.addField(Messages.getMessage("Embed.DisCal.Settings.Channel", settings), dChannel, false)
.addField(Messages.getMessage("Embed.DisCal.Settings.SimpleAnn", settings),
settings.getSimpleAnnouncements() + "", true)
.addField(Messages.getMessage("Embed.DisCal.Settings.Patron", settings), settings.getPatronGuild() + "", true)
.addField(Messages.getMessage("Embed.DisCal.Settings.Dev", settings), settings.getDevGuild() + "", true)
.addField(Messages.getMessage("Embed.DisCal.Settings.MaxCal", settings), settings.getMaxCalendars() + "", true)
.addField(Messages.getMessage("Embed.DisCal.Settings.Language", settings), settings.getLang(), true)
.addField(Messages.getMessage("Embed.DisCal.Settings.Prefix", settings), settings.getPrefix(), true)
//TODO: Add translations...
.addField("Using Twelve Hour Format", settings.getTwelveHour() + "", true)
.addField("Using Branding", settings.getBranded() + "", true)
.footer(Messages.getMessage("Embed.DisCal.Info.Patron", settings) + ": https://www.patreon.com/Novafox",
null)
.url(BotSettings.BASE_URL.get())
.color(GlobalVal.getDiscalColor());
if (settings.getBranded())
builder.author(guild.getName(), BotSettings.BASE_URL.get(),
guild.getIconUrl(Image.Format.PNG).orElse(GlobalVal.getIconUrl()));
else
builder.author("DisCal", BotSettings.BASE_URL.get(), GlobalVal.getIconUrl());
return builder.build();
}));
return embedMono.flatMap(embed -> Messages.sendMessage(embed, event)).then();
}
private Mono<Void> moduleDmAnnouncements(final MessageCreateEvent event, final GuildSettings settings) {
return Mono.just(settings.getDevGuild())
.filter(identity -> identity)
@@ -284,70 +202,11 @@ public class DisCalCommand implements Command {
.then();
}
private Mono<Void> moduleLanguage(final String[] args, final MessageCreateEvent event, final GuildSettings settings) {
return PermissionChecker.hasManageServerRole(event)
.filter(identity -> identity)
.flatMap(ignore -> {
if (args.length == 2) {
final String value = args[1];
if (Messages.isSupported(value)) {
final String valid = Messages.getValidLang(value);
settings.setLang(valid);
return DatabaseManager.INSTANCE.updateSettings(settings)
.then(Messages.sendMessage(Messages.getMessage("DisCal.Lang.Success", settings), event));
} else {
final String langs = Messages.getLangs().toString().replace("[", "").replace("]", "");
return Messages.sendMessage(
Messages.getMessage("DisCal.Lang.Unsupported", "%values%", langs, settings), event);
}
} else {
final String langs = Messages.getLangs().toString().replace("[", "").replace("]", "");
return Messages.sendMessage(
Messages.getMessage("DisCal.Lang.Unsupported", "%values%", langs, settings), event);
}
})
.switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings), event))
.then();
}
private Mono<Void> moduleInvite(final MessageCreateEvent event, final GuildSettings settings) {
return Messages.sendMessage(Messages.getMessage("DisCal.InviteLink", "%link%",
BotSettings.SUPPORT_INVITE.get(), settings), event).then();
}
private Mono<Void> moduleBrand(final MessageCreateEvent event, final GuildSettings settings) {
return PermissionChecker.hasManageServerRole(event)
.filter(identity -> identity)
.map(b -> settings.getPatronGuild())
.flatMap(isPatron -> {
if (isPatron) {
settings.setBranded(!settings.getBranded());
return DatabaseManager.INSTANCE.updateSettings(settings)
.then(Messages.sendMessage(
Messages.getMessage("DisCal.Brand", "%value%", settings.getBranded() + "", settings),
event));
} else {
return Messages.sendMessage(Messages.getMessage("Notification.Patron", settings), event);
}
})
.switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings), event))
.then();
}
private Mono<Void> moduleTwelveHour(MessageCreateEvent event, GuildSettings settings) {
return PermissionChecker.hasManageServerRole(event)
.filter(identity -> identity)
.then(Mono.just(settings))
.doOnNext(s -> s.setTwelveHour(!s.getTwelveHour()))
.flatMap(DatabaseManager.INSTANCE::updateSettings)
//TODO: Add translations
.then(Messages.sendMessage("Twelve hour time format use changed to: " + !settings.getTwelveHour(), event))
.switchIfEmpty(Messages.sendMessage(Messages.getMessage("Notification.Perm.MANAGE_SERVER", settings),
event))
.then();
}
private Mono<Void> moduleDashboard(final MessageCreateEvent event, final GuildSettings settings) {
return Messages.sendMessage(Messages.getMessage("DisCal.DashboardLink", "%link%",
GlobalVal.getDiscalDashboardLink(), settings), event).then();

View File

@@ -0,0 +1,105 @@
package org.dreamexposure.discal.client.commands
import discord4j.core.`object`.command.ApplicationCommandInteractionOptionValue
import discord4j.core.event.domain.interaction.SlashCommandEvent
import org.dreamexposure.discal.client.message.Responder
import org.dreamexposure.discal.client.message.embed.SettingsEmbed
import org.dreamexposure.discal.core.`object`.GuildSettings
import org.dreamexposure.discal.core.database.DatabaseManager
import org.dreamexposure.discal.core.enums.announcement.AnnouncementStyle
import org.dreamexposure.discal.core.enums.time.TimeFormat
import org.dreamexposure.discal.core.extensions.discord4j.hasElevatedPermissions
import org.dreamexposure.discal.core.utils.getCommonMsg
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono
@Component
class SettingsCommand : SlashCommand {
override val name = "settings"
override val ephemeral = true
override fun handle(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
//Check if user has permission to use this
return event.interaction.member.get().hasElevatedPermissions().flatMap { hasPerm ->
if (hasPerm) {
return@flatMap when (event.options[0].name) {
"view" -> viewSubcommand(event, settings)
"role" -> roleSubcommand(event, settings)
"announcement-style" -> announcementStyleSubcommand(event, settings)
"language" -> languageSubcommand(event, settings)
"time-format" -> timeFormatSubcommand(event, settings)
"branding" -> brandingSubcommand(event, settings)
else -> Mono.empty() //Never can reach this, makes compiler happy.
}
} else {
Responder.followupEphemeral(event, getCommonMsg("error.perms.manageServer", settings)).then()
}
}
}
private fun viewSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return event.interaction.guild
.flatMap { SettingsEmbed.getView(it, settings) }
.flatMap { Responder.followup(event, it) }
.then()
}
private fun roleSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return Mono.justOrEmpty(event.options[0].getOption("role"))
.map { it.value.get() }
.flatMap(ApplicationCommandInteractionOptionValue::asRole)
.doOnNext { settings.controlRole = it.id.asString() }
.flatMap { role ->
DatabaseManager.updateSettings(settings)
.then(Responder.followupEphemeral(event, getMessage("role.success", settings, role.name)))
}.then()
}
private fun announcementStyleSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return Mono.justOrEmpty(event.options[0].getOption("style"))
.map { it.value.get() }
.map { AnnouncementStyle.fromValue(it.asLong().toInt()) }
.doOnNext { settings.announcementStyle = it }
.flatMap { DatabaseManager.updateSettings(settings) }
.then(Responder.followupEphemeral(
event,
getMessage("style.success", settings, settings.announcementStyle.name)
)).then()
}
private fun languageSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return Mono.justOrEmpty(event.options[0].getOption("lang"))
.map { it.value.get() }
.map(ApplicationCommandInteractionOptionValue::asString)
.doOnNext { settings.lang = it }
.flatMap { DatabaseManager.updateSettings(settings) }
.then(Responder.followupEphemeral(event, getMessage("lang.success", settings)))
.then()
}
private fun timeFormatSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return Mono.justOrEmpty(event.options[0].getOption("format"))
.map { it.value.get() }
.map { TimeFormat.fromValue(it.asLong().toInt()) }
.doOnNext { settings.timeFormat = it }
.flatMap { DatabaseManager.updateSettings(settings) }
.then(Responder.followupEphemeral(
event,
getMessage("format.success", settings, settings.timeFormat.name)
)).then()
}
private fun brandingSubcommand(event: SlashCommandEvent, settings: GuildSettings): Mono<Void> {
return if (settings.patronGuild) {
settings.branded = !settings.branded
DatabaseManager.updateSettings(settings)
.then(Responder.followupEphemeral(
event,
getMessage("brand.success", settings, "${settings.branded}")
)).then()
} else {
Responder.followupEphemeral(event, getCommonMsg("error.patronOnly", settings)).then()
}
}
}

View File

@@ -3,6 +3,7 @@ package org.dreamexposure.discal.client.message.embed
import discord4j.core.`object`.entity.Guild
import discord4j.core.spec.EmbedCreateSpec
import org.dreamexposure.discal.core.`object`.GuildSettings
import org.dreamexposure.discal.core.enums.time.TimeFormat
import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
import org.dreamexposure.discal.core.utils.GlobalVal.discalColor
import reactor.core.publisher.Mono
@@ -35,7 +36,7 @@ object CalendarEmbed : EmbedMaker {
val ldt = LocalDateTime.now(cal.timezone)
val fmt: DateTimeFormatter =
if (settings.twelveHour)
if (settings.timeFormat == TimeFormat.TWELVE_HOUR)
DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss a")
else
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")

View File

@@ -0,0 +1,32 @@
package org.dreamexposure.discal.client.message.embed
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.Guild
import discord4j.core.`object`.entity.Role
import discord4j.core.spec.EmbedCreateSpec
import org.dreamexposure.discal.core.`object`.GuildSettings
import reactor.core.publisher.Mono
object SettingsEmbed : EmbedMaker {
fun getView(guild: Guild, settings: GuildSettings): Mono<EmbedCreateSpec> {
val roleMono = guild.getRoleById(Snowflake.of(settings.controlRole))
.map(Role::getName)
.onErrorReturn("everyone") // This should be more efficient than looping through all roles
return roleMono.map { roleName ->
defaultBuilder(guild, settings)
.title(getMessage("settings", "view.title", settings))
.addField(getMessage("settings", "view.field.role", settings), roleName, false)
.addField(getMessage("settings", "view.field.style", settings), settings.announcementStyle.name, true)
.addField(getMessage("settings", "view.field.format", settings), settings.timeFormat.name, true)
.addField(getMessage("settings", "view.field.lang", settings), settings.getLocale().displayName, false)
.addField(getMessage("settings", "view.field.patron", settings), "${settings.patronGuild}", true)
.addField(getMessage("settings", "view.field.dev", settings), "${settings.devGuild}", true)
.addField(getMessage("settings", "view.field.cal", settings), "${settings.maxCalendars}", true)
.addField(getMessage("settings", "view.field.brand", settings), "${settings.branded}", false)
.footer(getMessage("settings", "view.footer", settings), null)
.build()
}
}
}

View File

@@ -1,10 +1,5 @@
package org.dreamexposure.discal.core.utils;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.GuildSettings;
import java.util.function.Predicate;
import discord4j.common.util.Snowflake;
import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.entity.Member;
@@ -17,14 +12,19 @@ import discord4j.rest.entity.RestGuild;
import discord4j.rest.entity.RestMember;
import discord4j.rest.util.Permission;
import discord4j.rest.util.PermissionSet;
import org.dreamexposure.discal.core.object.BotSettings;
import org.dreamexposure.discal.core.object.GuildSettings;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.function.Predicate;
/**
* Created by Nova Fox on 1/19/17.
* Website: www.cloudcraftgaming.com
* For Project: DisCal
*/
@Deprecated
public class PermissionChecker {
public static Mono<Boolean> hasDisCalRole(final MessageCreateEvent event, final GuildSettings settings) {
if ("everyone".equalsIgnoreCase(settings.getControlRole()))

View File

@@ -1,6 +1,6 @@
package org.dreamexposure.discal.core.utils;
import org.dreamexposure.discal.core.enums.timezone.BadTimezone;
import org.dreamexposure.discal.core.enums.time.BadTimezone;
import java.time.ZoneId;

View File

@@ -12,7 +12,7 @@ enum class AnnouncementModifier {
}
fun fromValue(value: String): AnnouncementModifier {
return when (value.toUpperCase()) {
return when (value.uppercase()) {
"DURING" -> DURING
"END" -> END
else -> BEFORE

View File

@@ -0,0 +1,20 @@
package org.dreamexposure.discal.core.enums.announcement
enum class AnnouncementStyle(val value: Int = 1) {
FULL(1), SIMPLE(2), EVENT(3);
companion object {
fun isValid(i: Int): Boolean {
return i in 1..3
}
fun fromValue(i: Int): AnnouncementStyle {
return when (i) {
1 -> FULL
2 -> SIMPLE
3 -> EVENT
else -> FULL
}
}
}
}

View File

@@ -13,7 +13,7 @@ enum class AnnouncementType {
}
fun fromValue(value: String): AnnouncementType {
return when (value.toUpperCase()) {
return when (value.uppercase()) {
"SPECIFIC" -> SPECIFIC
"COLOR" -> COLOR
"COLOUR" -> COLOR

View File

@@ -1,4 +1,4 @@
package org.dreamexposure.discal.core.enums.timezone
package org.dreamexposure.discal.core.enums.time
enum class BadTimezone {
America_Adak,

View File

@@ -1,4 +1,4 @@
package org.dreamexposure.discal.core.enums.timezone
package org.dreamexposure.discal.core.enums.time
enum class GoodTimezone {
Africa___Abidjan,

View File

@@ -0,0 +1,20 @@
package org.dreamexposure.discal.core.enums.time
enum class TimeFormat(val value: Int = 1) {
TWENTY_FOUR_HOUR(1),
TWELVE_HOUR(2);
companion object {
fun isValid(i: Int): Boolean {
return i == 1 || i == 2
}
fun fromValue(i: Int): TimeFormat {
return when (i) {
1 -> TWENTY_FOUR_HOUR
2 -> TWELVE_HOUR
else -> TWENTY_FOUR_HOUR
}
}
}
}

View File

@@ -0,0 +1,14 @@
package org.dreamexposure.discal.core.extensions.discord4j
import discord4j.core.`object`.entity.Member
import discord4j.rest.entity.RestMember
import discord4j.rest.util.PermissionSet
import java.util.function.Predicate
fun Member.hasPermissions(pred: Predicate<PermissionSet>) = getRestMember().hasPermissions(pred)
fun Member.hasElevatedPermissions() = getRestMember().hasElevatedPermissions()
fun Member.hasControlRole() = getRestMember().hasControlRole()
fun Member.getRestMember(): RestMember = client.rest().restMember(guildId, memberData)

View File

@@ -0,0 +1,48 @@
package org.dreamexposure.discal.core.extensions.discord4j
import discord4j.common.util.Snowflake
import discord4j.discordjson.Id
import discord4j.discordjson.json.GuildUpdateData
import discord4j.discordjson.json.MemberData
import discord4j.discordjson.json.RoleData
import discord4j.rest.entity.RestMember
import discord4j.rest.util.Permission
import discord4j.rest.util.PermissionSet
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.util.function.Predicate
fun RestMember.hasPermissions(pred: Predicate<PermissionSet>): Mono<Boolean> {
return this.data.flatMap { memberData ->
this.guild().data.map(GuildUpdateData::roles)
.flatMapMany { Flux.fromIterable(it) }
.filter { memberData.roles().contains(it.id()) }
.map(RoleData::permissions)
.reduce(0L) { perm: Long, accumulator: Long -> accumulator or perm }
.map(PermissionSet::of)
.map(pred::test)
}
}
fun RestMember.hasElevatedPermissions(): Mono<Boolean> {
return hasPermissions() {
it.contains(Permission.MANAGE_GUILD) || it.contains(Permission.ADMINISTRATOR)
}
}
fun RestMember.hasControlRole(): Mono<Boolean> {
return this.guild().getSettings().flatMap { settings ->
if (settings.controlRole.equals("everyone", true))
return@flatMap Mono.just(true)
if (Snowflake.of(settings.controlRole).equals(settings.guildID)) // Also everyone (older guilds)
return@flatMap Mono.just(true)
this.data
.map(MemberData::roles)
.flatMapMany { Flux.fromIterable(it) }
.map(Id::asString)
.collectList()
.map { it.contains(settings.controlRole) }
}
}

View File

@@ -3,35 +3,39 @@ package org.dreamexposure.discal.core.`object`
import discord4j.common.util.Snowflake
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.dreamexposure.discal.core.enums.announcement.AnnouncementStyle
import org.dreamexposure.discal.core.enums.time.TimeFormat
import org.dreamexposure.discal.core.extensions.asStringList
import org.dreamexposure.discal.core.serializers.SnowflakeAsStringSerializer
import java.util.*
@Serializable
data class GuildSettings(
@Serializable(with = SnowflakeAsStringSerializer::class)
@Serializable(with = SnowflakeAsStringSerializer::class)
@SerialName("guild_id")
val guildID: Snowflake,
@SerialName("control_role")
@SerialName("control_role")
var controlRole: String = "everyone",
@SerialName("discal_channel")
@SerialName("discal_channel")
var discalChannel: String = "all",
@SerialName("simple_announcement")
var simpleAnnouncements: Boolean = false,
var lang: String = "ENGLISH",
var prefix: String = "!",
@SerialName("announcement_style")
var announcementStyle: AnnouncementStyle = AnnouncementStyle.FULL,
@SerialName("time_format")
var timeFormat: TimeFormat = TimeFormat.TWENTY_FOUR_HOUR,
@SerialName("patron_guild")
var lang: String = "ENGLISH",
var prefix: String = "!",
@SerialName("patron_guild")
var patronGuild: Boolean = false,
@SerialName("dev_guild")
@SerialName("dev_guild")
var devGuild: Boolean = false,
@SerialName("max_calendars")
@SerialName("max_calendars")
var maxCalendars: Int = 1,
@SerialName("twelve_hour")
var twelveHour: Boolean = true,
var branded: Boolean = false,
var branded: Boolean = false,
) {
@SerialName("")
val dmAnnouncements: MutableList<String> = mutableListOf()
@@ -40,18 +44,7 @@ data class GuildSettings(
fun empty(guildId: Snowflake) = GuildSettings(guildId)
}
fun getDmAnnouncementsString(): String {
val dm = StringBuilder()
for ((i, sub) in this.dmAnnouncements.withIndex()) {
if (sub.isNotBlank()) {
if (i == 0) dm.append(sub)
else dm.append(",").append(sub)
}
}
return dm.toString()
}
fun getDmAnnouncementsString() = this.dmAnnouncements.asStringList()
fun setDmAnnouncementsString(dm: String) {
this.dmAnnouncements += dm.split(",").filter(String::isNotBlank)

View File

@@ -36,8 +36,8 @@ data class WebGuild(
@SerialName("bot_nick")
val botNick: String? = null,
@SerialName("manage_server")
var manageServer: Boolean = false,
@SerialName("elevated_access")
var elevatedAccess: Boolean = false,
@SerialName("discal_role")
var discalRole: Boolean = false,
@@ -88,7 +88,7 @@ data class WebGuild(
Mono.zip(botNick, settings, roles, webChannels, announcements, calendar)
.map(TupleUtils.function { bn, s, r, wc, a, c ->
WebGuild(id.asLong(), name, ico, s, bn, manageServer = false, discalRole = false, c).apply {
WebGuild(id.asLong(), name, ico, s, bn, elevatedAccess = false, discalRole = false, c).apply {
this.roles.addAll(r)
this.channels.add(WebChannel.all(s))
this.channels.addAll(wc)
@@ -131,7 +131,7 @@ data class WebGuild(
return Mono.zip(botNick, settings, roles, channels, announcements, calendar)
.map(TupleUtils.function { bn, s, r, wc, a, c ->
WebGuild(id, name, icon, s, bn, manageServer = false, discalRole = false, c).apply {
WebGuild(id, name, icon, s, bn, elevatedAccess = false, discalRole = false, c).apply {
this.roles.addAll(r)
this.channels.add(WebChannel.all(s))
this.channels.addAll(wc)

View File

@@ -30,21 +30,21 @@
"options": [
{
"name": "style",
"type": 3,
"type": 4,
"description": "The announcement style to use",
"required": true,
"choices": [
{
"name": "full",
"value": "FULL"
"name": "Full",
"value": 1
},
{
"name": "simple",
"value": "SIMPLE"
"name": "Simple",
"value": 2
},
{
"name": "event only",
"value": "EVENT"
"name": "Event Only",
"value": 3
}
]
}
@@ -74,7 +74,25 @@
"name": "time-format",
"type": 1,
"description": "Toggles between 24-hour and 12-hour time formatting",
"required": false
"required": false,
"options": [
{
"name": "format",
"type": 4,
"description": "The format to use",
"required": true,
"choices": [
{
"name": "24 Hour",
"value": 1
},
{
"name": "12 Hour",
"value": 2
}
]
}
]
},
{
"name": "branding",

View File

@@ -0,0 +1,11 @@
# Delete simple announcement
ALTER TABLE ${prefix}guild_settings
DROP COLUMN SIMPLE_ANNOUNCEMENT,
DROP COLUMN 12_HOUR;
# Add announcement_format
ALTER TABLE ${prefix}guild_settings
ADD COLUMN announcement_style TINYINT default 1,
ADD COLUMN time_format TINYINT default 1
after DISCAL_CHANNEL;

View File

@@ -2,18 +2,13 @@ meta.description=Used for changing settings related to DisCal
meta.example=/settings (subcommand) (args...)
meta.description.view=Displays the bot's settings for this guild
meta.description.role=Sets the role users need for some commands
meta.description.simpleAnnouncement=Makes announcements more friendly
meta.description.announcement-style=Changes how announcements are styled
meta.description.language=Sets the default language the bot will use in this server
meta.description.brand=Toggles server branding (hiding bot name/logo where possible)
meta.description.twelveHour=Toggles between a 12-hour or 24-hour time format
meta.description.time-format=Changes to format to use for displaying non-localized times
role.success.reset=Role has been reset. Anyone can create/edit events/announcements.
role.success.set=Required role needed to use DisCal creation commands set to `{0}`
role.failure.notFound=Could not find that role. Maybe its misspelled?
role.failure.badArgs=Invalid arguments were supplied. See command info with `/help discal role`
channel.success.reset=Channel has been reset. DisCal can now be used in any channel with correct permissions.
simpleAnnouncement.success=Simple announcement setting has been toggled to `{0}`.
timeFormat.success=Use 12-hour time format setting has been toggled to `{0}`.
language.success=Successfully changed default language!
language.failure.notSupported=Language not found. Currently supported languages are: {0}
language.failure.badArgs=Invalid arguments were supplied. See command info with `/help discal language`
role.success=Required role needed to use protected commands set to `{0}`
style.success=Announcement Style successfully changed to `{0}`.
lang.success=Successfully changed default language!
format.success=Time Format successfully changed to `{0}`.
brand.success=Server Branding toggled to `{0}`.

View File

@@ -3,7 +3,8 @@ error.notFound.event=No event with that ID was found.
error.notFound.calendar=Calendar not found. Perhaps create a new calendar?
error.notFound.role=No role based on your input was found. Try being more specific, or use the role's ID.
error.notFound.announcement=No announcement with that ID was found.
error.perms.manageServer=This feature requires elevated permissions (manage server), please contact the server owner.
error.perms.manageServer=This feature requires elevated permissions (admin/manage server), please contact the server \
owner.
error.perms.controlRole=This feature requires the role assigned for elevated permissions for DisCal.
error.input.notNumber=The value needs to be a whole number. For example: `5` or `10`
error.disabled=This feature is currently disabled for maintenance.

View File

@@ -1,14 +1,14 @@
full.title=Event Info
full.field.name=Name
full.field.desc=Description
full.field.start=Event Start
full.field.end=Event End
full.field.start=Event Start (Local)
full.field.end=Event End (Local)
full.field.location=Location
full.field.cal=Calendar
full.footer=Event ID: {0}
con.title=Condensed Event Info
con.field.name=Name
con.field.start=Start
con.field.start=Start (Local)
con.field.location=Location
con.footer=Event ID: {0}

View File

@@ -0,0 +1,10 @@
view.title=DisCal Guild Settings
view.field.role=Control Role
view.field.style=Announcement Style
view.field.format=Time Format
view.field.lang=Language
view.field.patron=Patron Guild
view.field.dev=Dev Guild
view.field.cal=Max Calendars
view.field.brand=Using Branding
view.footer=Become a patron today and support DisCal! https://www.patreon.com/Novafox

View File

@@ -5,10 +5,11 @@ import discord4j.core.DiscordClient
import kotlinx.serialization.encodeToString
import org.dreamexposure.discal.core.`object`.web.WebGuild
import org.dreamexposure.discal.core.exceptions.BotNotInGuildException
import org.dreamexposure.discal.core.extensions.discord4j.hasControlRole
import org.dreamexposure.discal.core.extensions.discord4j.hasElevatedPermissions
import org.dreamexposure.discal.core.file.ReadFile
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.core.utils.PermissionChecker
import org.dreamexposure.discal.server.utils.Authentication
import org.dreamexposure.discal.server.utils.responseMessage
import org.json.JSONException
@@ -44,17 +45,17 @@ class GetWebGuildEndpoint(val client: DiscordClient) {
WebGuild.fromGuild(g).flatMap { wg ->
val member = g.member(userId)
val manageServerMono = PermissionChecker.hasManageServerRole(member, g)
val discalRoleMono = PermissionChecker.hasSufficientRole(member, wg.settings)
val elevatedMono = member.hasElevatedPermissions()
val discalRoleMono = member.hasControlRole()
val langsMono = ReadFile.readAllLangFiles()
.map { it.keySet() }
.flatMapMany { Flux.fromIterable(it) }
.map { it as String }
.collectList()
Mono.zip(manageServerMono, discalRoleMono, langsMono)
.map(TupleUtils.function { manageServer, discalRole, langs ->
wg.manageServer = manageServer
Mono.zip(elevatedMono, discalRoleMono, langsMono)
.map(TupleUtils.function { elevated, discalRole, langs ->
wg.elevatedAccess = elevated
wg.discalRole = discalRole
wg.availableLangs.addAll(langs)

View File

@@ -3,6 +3,8 @@ package org.dreamexposure.discal.server.endpoints.v2.guild.settings
import discord4j.common.util.Snowflake
import kotlinx.serialization.encodeToString
import org.dreamexposure.discal.core.database.DatabaseManager
import org.dreamexposure.discal.core.enums.announcement.AnnouncementStyle
import org.dreamexposure.discal.core.enums.time.TimeFormat
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.server.utils.Authentication
@@ -43,10 +45,10 @@ class UpdateGuildSettingsEndpoint {
val id = body.getString("discal_channel")
disChannel = if (id.equals("0") || id.equals("all", true)) "all" else id
}
val simpleAnn = body.optBoolean("simple_announcements", settings.simpleAnnouncements)
val aStyle = body.optInt("announcement_style", settings.announcementStyle.value)
val lang = body.optString("lang", settings.lang)
val prefix = body.optString("prefix", settings.prefix)
val twelveHour = body.optBoolean("twelve_hour", settings.twelveHour)
val timeFormat = body.optInt("time_format", settings.timeFormat.value)
var patronGuild = settings.patronGuild
var devGuild = settings.devGuild
var branded = settings.branded
@@ -60,18 +62,21 @@ class UpdateGuildSettingsEndpoint {
maxCals = body.optInt("max_calendars", maxCals)
}
val newSettings = settings.copy(controlRole = conRole, discalChannel = disChannel,
simpleAnnouncements = simpleAnn, lang = lang,
prefix = prefix, patronGuild = patronGuild,
devGuild = devGuild, maxCalendars = maxCals,
twelveHour = twelveHour, branded = branded
val newSettings = settings.copy(controlRole = conRole,
discalChannel = disChannel,
announcementStyle = AnnouncementStyle.fromValue(aStyle),
timeFormat = TimeFormat.fromValue(timeFormat),
lang = lang,
prefix = prefix, patronGuild = patronGuild,
devGuild = devGuild, maxCalendars = maxCals,
branded = branded
)
DatabaseManager.updateSettings(newSettings)
.then(responseMessage("Success"))
.doOnNext {
response.rawStatusCode = GlobalVal.STATUS_SUCCESS
}
.then(responseMessage("Success"))
.doOnNext {
response.rawStatusCode = GlobalVal.STATUS_SUCCESS
}
}
}.onErrorResume(JSONException::class.java) {
LOGGER.trace("[API-v2] JSON error. Bad request?", it)

View File

@@ -0,0 +1,5 @@
export enum AnnouncementStyle {
FULL = 1,
SIMPLE = 2,
EVENT = 3
}

View File

@@ -0,0 +1,4 @@
export enum TimeFormat {
TWENTY_FOUR_HOUR = 1,
TWELVE_HOUR = 2
}

View File

@@ -1,14 +1,17 @@
import {TimeFormat} from "@/enums/TimeFormat";
import {AnnouncementStyle} from "@/enums/AnnouncementStyle";
export class GuildSettings {
private _id: string;
private _controlRole: string = "everyone";
private _disCalChannel: string = "all";
private _hasSimpleAnnouncements: boolean = false;
private _announcementStyle: AnnouncementStyle = AnnouncementStyle.FULL;
private _lang: string = "";
private _prefix: string = "";
private _isPatronGuild: boolean = false;
private _isDevGuild: boolean = false;
private _maxCalendars: number = 1;
private _usingTwelveHour: boolean = false;
private _timeFormat: TimeFormat = TimeFormat.TWENTY_FOUR_HOUR;
private _isBranded: boolean = false;
constructor(id: string) {
@@ -36,12 +39,12 @@ export class GuildSettings {
this._disCalChannel = channel;
}
get hasSimpleAnnouncements() {
return this._hasSimpleAnnouncements;
get announcementStyle() {
return this._announcementStyle;
}
set hasSimpleAnnouncements(simpleAnnouncements) {
this._hasSimpleAnnouncements = simpleAnnouncements;
set announcementStyle(style) {
this._announcementStyle = style;
}
get lang() {
@@ -84,12 +87,12 @@ export class GuildSettings {
this._maxCalendars = max;
}
get usingTwelveHour() {
return this._usingTwelveHour;
get timeFormat() {
return this._timeFormat;
}
set usingTwelveHour(using) {
this._usingTwelveHour = using;
set timeFormat(format) {
this._timeFormat = format;
}
get isBranded() {
@@ -106,13 +109,13 @@ export class GuildSettings {
"guild_id": this.id,
"control_role": this.controlRole,
"discal_channel": this.disCalChannel,
"simple_announcement": this.hasSimpleAnnouncements,
"announcement_style": this.announcementStyle,
"lang": this.lang,
"prefix": this.prefix,
"patron_guild": this.isPatronGuild,
"dev_guild": this.isDevGuild,
"max_calendars": this.maxCalendars,
"twelve_hour": this.usingTwelveHour,
"time_format": this.timeFormat,
"branded": this.isBranded
};
}
@@ -121,13 +124,13 @@ export class GuildSettings {
this._id = json.guild_id;
this.controlRole = json.control_role;
this.disCalChannel = json.discal_channel;
this.hasSimpleAnnouncements = json.simple_announcement;
this.announcementStyle = json.announcement_style;
this.lang = json.lang;
this.prefix = json.prefix;
this.isPatronGuild = json.patron_guild;
this.isDevGuild = json.dev_guild;
this.maxCalendars = json.max_calendars;
this.usingTwelveHour = json.twelve_hour;
this.timeFormat = json.time_format;
this.isBranded = json.branded;
return this;

View File

@@ -12,7 +12,7 @@ export class WebGuild {
private _settings: GuildSettings = new GuildSettings("");
private _botNick: string = "";
private _canManageServer: boolean = false;
private _elevatedAccess: boolean = false;
private _hasDisCalRole: boolean = false;
private readonly _roles: WebRole[] = [];
@@ -65,12 +65,12 @@ export class WebGuild {
this._botNick = nick;
}
get canManageServer() {
return this._canManageServer;
get hasElevatedAccess() {
return this._elevatedAccess;
}
set canManageServer(manage) {
this._canManageServer = manage;
set hasElevatedAccess(access) {
this._elevatedAccess = access;
}
get hasDisCalRole() {
@@ -119,7 +119,7 @@ export class WebGuild {
"id": this.id,
"name": this.name,
"settings": this.settings.toJson(),
"manage_server": this.canManageServer,
"elevated_access": this.hasElevatedAccess,
"discal_role": this.hasDisCalRole,
"calendar": this.calendar.toJson()
};
@@ -170,7 +170,7 @@ export class WebGuild {
this.botNick = json.bot_nick;
}
this.canManageServer = json.manage_server;
this.hasElevatedAccess = json.elevated_access;
this.hasDisCalRole = json.discal_role;
for (let i = 0; i < json.roles.length; i++) {

View File

@@ -8,7 +8,7 @@ import org.dreamexposure.discal.core.`object`.BotSettings
import org.dreamexposure.discal.core.`object`.web.WebPartialGuild
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType
import org.dreamexposure.discal.core.enums.event.EventColor
import org.dreamexposure.discal.core.enums.timezone.GoodTimezone
import org.dreamexposure.discal.core.enums.time.GoodTimezone
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.web.handler.DiscordAccountHandler