mirror of
https://github.com/DreamExposure/DisCal-Discord-Bot.git
synced 2026-01-23 12:29:31 -06:00
Announcement runner rewrite (#114)
Full rewrite of the announcement runner in kotlin and remove several now-unused deprecated methods
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Credit to Discord4J for the .editorconfig file <3
|
||||
@@ -26,7 +26,7 @@ val discord4jVersion = "3.2.0" //Has to be here to show up in git properties tas
|
||||
allprojects {
|
||||
//Project props
|
||||
group = "org.dreamexposure.discal"
|
||||
version = "4.1.2"
|
||||
version = "4.1.3-SNAPSHOT"
|
||||
description = "DisCal"
|
||||
|
||||
//Plugins
|
||||
|
||||
@@ -2,28 +2,23 @@ package org.dreamexposure.discal.client.message;
|
||||
|
||||
import com.google.api.services.calendar.model.Event;
|
||||
import discord4j.common.util.Snowflake;
|
||||
import discord4j.core.object.entity.*;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Role;
|
||||
import discord4j.core.object.entity.channel.GuildChannel;
|
||||
import discord4j.core.object.entity.channel.GuildMessageChannel;
|
||||
import discord4j.core.spec.EmbedCreateSpec;
|
||||
import discord4j.rest.http.client.ClientException;
|
||||
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;
|
||||
import org.dreamexposure.discal.core.object.GuildSettings;
|
||||
import org.dreamexposure.discal.core.object.announcement.Announcement;
|
||||
import org.dreamexposure.discal.core.object.calendar.CalendarData;
|
||||
import org.dreamexposure.discal.core.object.event.EventData;
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal;
|
||||
import org.dreamexposure.discal.core.utils.ImageUtils;
|
||||
import org.dreamexposure.discal.core.utils.RoleUtils;
|
||||
import org.dreamexposure.discal.core.utils.UserUtils;
|
||||
import org.dreamexposure.discal.core.wrapper.google.CalendarWrapper;
|
||||
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -68,7 +63,7 @@ public class AnnouncementMessageFormatter {
|
||||
embed.author("DisCal", BotSettings.BASE_URL.get(), GlobalVal.getIconUrl());
|
||||
|
||||
embed.title(Messages.getMessage("Embed.Announcement.Info.Title", settings));
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Info.ID", settings), a.getAnnouncementId().toString(), true);
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Info.ID", settings), a.getId().toString(), true);
|
||||
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Info.Type", settings), a.getType().name(), true);
|
||||
|
||||
@@ -135,7 +130,7 @@ public class AnnouncementMessageFormatter {
|
||||
embed.author("DisCal", BotSettings.BASE_URL.get(), GlobalVal.getIconUrl());
|
||||
|
||||
embed.title(Messages.getMessage("Embed.Announcement.Condensed.Title", settings));
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.ID", settings), a.getAnnouncementId().toString(), false);
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.ID", settings), a.getId().toString(), false);
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.Time", settings), condensedTime(a), false);
|
||||
|
||||
if (a.getType().equals(AnnouncementType.SPECIFIC)) {
|
||||
@@ -172,238 +167,6 @@ public class AnnouncementMessageFormatter {
|
||||
}));
|
||||
}
|
||||
|
||||
public static Mono<EmbedCreateSpec> getCondensedAnnouncementEmbed(Announcement a, int calNum,
|
||||
GuildSettings settings) {
|
||||
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
|
||||
|
||||
Mono<Event> event = Mono.just(a)
|
||||
.map(Announcement::getType)
|
||||
.filter(t -> t.equals(AnnouncementType.SPECIFIC))
|
||||
.flatMap(t -> DatabaseManager.INSTANCE.getCalendar(a.getGuildId(), calNum))
|
||||
.flatMap(cd -> EventWrapper.INSTANCE.getEvent(cd, a.getEventId()))
|
||||
.defaultIfEmpty(new Event());
|
||||
|
||||
Mono<EventData> eData = Mono.just(a)
|
||||
.map(Announcement::getType)
|
||||
.filter(t -> t.equals(AnnouncementType.SPECIFIC) || t.equals(AnnouncementType.RECUR))
|
||||
.flatMap(t -> DatabaseManager.INSTANCE.getEventData(a.getGuildId(), a.getEventId()))
|
||||
.defaultIfEmpty(new EventData()).cache();
|
||||
|
||||
Mono<Boolean> img = eData.filter(EventData::shouldBeSaved)
|
||||
.flatMap(ed -> ImageUtils.validate(ed.getImageLink(), settings.getPatronGuild()))
|
||||
.defaultIfEmpty(false);
|
||||
|
||||
|
||||
return Mono.zip(guild, event, eData, img)
|
||||
.map(TupleUtils.function((g, e, ed, hasImg) -> {
|
||||
var embed = EmbedCreateSpec.builder();
|
||||
|
||||
if (settings.getBranded())
|
||||
embed.author(g.getName(), BotSettings.BASE_URL.get(),
|
||||
g.getIconUrl(Image.Format.PNG).orElse(GlobalVal.getIconUrl()));
|
||||
else
|
||||
embed.author("DisCal", BotSettings.BASE_URL.get(), GlobalVal.getIconUrl());
|
||||
|
||||
embed.title(Messages.getMessage("Embed.Announcement.Condensed.Title", settings));
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.ID", settings), a.getAnnouncementId().toString(), false);
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.Time", settings), condensedTime(a), false);
|
||||
|
||||
if (a.getType().equals(AnnouncementType.SPECIFIC)) {
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.EventID", settings), a.getEventId(), false);
|
||||
|
||||
if (hasImg)
|
||||
embed.thumbnail(ed.getImageLink());
|
||||
|
||||
if (e.getSummary() != null) {
|
||||
String summary = e.getSummary();
|
||||
if (summary.length() > 250) {
|
||||
summary = summary.substring(0, 250);
|
||||
summary = summary + " (continues on Google Calendar View)";
|
||||
}
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.Summary", settings), summary, true);
|
||||
}
|
||||
} else if (a.getType().equals(AnnouncementType.COLOR)) {
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.Color", settings), a.getEventColor().name(), true);
|
||||
} else if (a.getType().equals(AnnouncementType.RECUR)) {
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Condensed.RecurID", settings), a.getEventId(), true);
|
||||
}
|
||||
embed.footer(Messages.getMessage("Embed.Announcement.Condensed.Type", "%type%", a.getType().name(),
|
||||
settings), null);
|
||||
|
||||
if (a.getType().equals(AnnouncementType.COLOR)) {
|
||||
embed.color(a.getEventColor().asColor());
|
||||
} else {
|
||||
embed.color(GlobalVal.getDiscalColor());
|
||||
}
|
||||
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Info.Enabled", settings), a.getEnabled() + "", true);
|
||||
|
||||
return embed.build();
|
||||
}));
|
||||
}
|
||||
|
||||
private static Mono<EmbedCreateSpec> getRealAnnouncementEmbed(Announcement a, Event event, CalendarData cd,
|
||||
GuildSettings settings) {
|
||||
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID());
|
||||
|
||||
Mono<String> startDate = EventMessageFormatter
|
||||
.getHumanReadableDate(event.getStart(), cd.getCalendarNumber(), false, settings);
|
||||
|
||||
Mono<String> startTime = EventMessageFormatter
|
||||
.getHumanReadableTime(event.getStart(), cd.getCalendarNumber(), false, settings);
|
||||
|
||||
Mono<String> timezone = CalendarWrapper.INSTANCE.getCalendar(cd)
|
||||
.map(com.google.api.services.calendar.model.Calendar::getTimeZone)
|
||||
.defaultIfEmpty("TZ Unknown/Error");
|
||||
|
||||
Mono<EventData> eData = DatabaseManager.INSTANCE.getEventData(settings.getGuildID(), event.getId())
|
||||
.defaultIfEmpty(new EventData())
|
||||
.cache();
|
||||
|
||||
Mono<Boolean> img = eData.filter(EventData::shouldBeSaved)
|
||||
.flatMap(ed -> ImageUtils.validate(ed.getImageLink(), settings.getPatronGuild()))
|
||||
.defaultIfEmpty(false);
|
||||
|
||||
return Mono.zip(guild, startDate, startTime, timezone, eData, img)
|
||||
.map(TupleUtils.function((g, sDate, sTime, tz, ed, hasImg) -> {
|
||||
var embed = EmbedCreateSpec.builder();
|
||||
|
||||
if (settings.getBranded())
|
||||
embed.author(g.getName(), BotSettings.BASE_URL.get(),
|
||||
g.getIconUrl(Image.Format.PNG).orElse(GlobalVal.getIconUrl()));
|
||||
else
|
||||
embed.author("DisCal", BotSettings.BASE_URL.get(), GlobalVal.getIconUrl());
|
||||
|
||||
embed.title(Messages.getMessage("Embed.Announcement.Announce.Title", settings));
|
||||
if (hasImg)
|
||||
embed.image(ed.getImageLink());
|
||||
|
||||
embed.url(event.getHtmlLink());
|
||||
|
||||
try {
|
||||
EventColor ec = EventColor.Companion.fromNameOrHexOrId(event.getColorId());
|
||||
embed.color(ec.asColor());
|
||||
} catch (Exception e) {
|
||||
//I dunno, color probably null.
|
||||
embed.color(GlobalVal.getDiscalColor());
|
||||
}
|
||||
|
||||
if (settings.getAnnouncementStyle() == AnnouncementStyle.FULL) {
|
||||
embed.footer(Messages.getMessage("Embed.Announcement.Announce.ID", "%id%",
|
||||
a.getAnnouncementId().toString(), settings), null);
|
||||
}
|
||||
|
||||
if (a.getInfoOnly() && !"none".equalsIgnoreCase(a.getInfo())) {
|
||||
//Only send info...
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Info", settings), a.getInfo(), false);
|
||||
} else {
|
||||
//Requires all announcement data
|
||||
if (event.getSummary() != null) {
|
||||
String summary = event.getSummary();
|
||||
if (summary.length() > 250) {
|
||||
summary = summary.substring(0, 250);
|
||||
summary = summary + " (continues on Google Calendar View)";
|
||||
}
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Summary", settings), summary, true);
|
||||
}
|
||||
if (event.getDescription() != null) {
|
||||
String description = event.getDescription();
|
||||
if (description.length() > 250) {
|
||||
description = description.substring(0, 250);
|
||||
description = description + " (continues on Google Calendar View)";
|
||||
}
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Description", settings), description, true);
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
String start = sDate + " at " + sTime + " " + tz;
|
||||
embed.addField(Messages.getMessage("Embed.Announcement.Announce.Start", settings), start, false);
|
||||
}
|
||||
|
||||
if (event.getLocation() != null && !"".equalsIgnoreCase(event.getLocation())) {
|
||||
if (event.getLocation().length() > 300) {
|
||||
String location = event.getLocation().substring(0, 300).trim() + "... (cont. on Google Cal)";
|
||||
embed.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), location, true);
|
||||
} else {
|
||||
embed.addField(Messages.getMessage("Embed.Event.Confirm.Location", settings), event.getLocation(), true);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return embed.build();
|
||||
}));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Mono<Void> sendAnnouncementMessage(Announcement a, Event event, CalendarData data,
|
||||
GuildSettings settings) {
|
||||
Mono<Guild> guild = DisCalClient.getClient().getGuildById(settings.getGuildID()).cache();
|
||||
|
||||
Mono<EmbedCreateSpec> embed = getRealAnnouncementEmbed(a, event, data, settings);
|
||||
Mono<String> mentions = guild.flatMap(g -> getSubscriberMentions(a, g));
|
||||
|
||||
return Mono.zip(guild, embed, mentions)
|
||||
.flatMap(TupleUtils.function((g, em, men) ->
|
||||
g.getChannelById(Snowflake.of(a.getAnnouncementChannelId()))
|
||||
.ofType(GuildMessageChannel.class)
|
||||
.onErrorResume(ClientException.class, e ->
|
||||
Mono.just(e.getStatus())
|
||||
.filter(HttpResponseStatus.NOT_FOUND::equals)
|
||||
.flatMap(ignored -> DatabaseManager.INSTANCE.deleteAnnouncement(a.getAnnouncementId().toString()))
|
||||
.then(Mono.empty()))
|
||||
.flatMap(chan -> {
|
||||
if (a.getPublish()) {
|
||||
return Messages.sendMessage(men, em, chan)
|
||||
.flatMap(Message::publish)
|
||||
.onErrorResume(e -> Mono.empty());
|
||||
} else
|
||||
return Messages.sendMessage(men, em, chan);
|
||||
})
|
||||
)).then();
|
||||
}
|
||||
|
||||
public static Mono<Void> sendAnnouncementMessage(Guild guild, Announcement a, Event event, CalendarData data,
|
||||
GuildSettings settings) {
|
||||
Mono<EmbedCreateSpec> embed = getRealAnnouncementEmbed(a, event, data, settings);
|
||||
Mono<String> mentions = getSubscriberMentions(a, guild);
|
||||
|
||||
return Mono.zip(embed, mentions)
|
||||
.flatMap(TupleUtils.function((em, men) ->
|
||||
guild.getChannelById(Snowflake.of(a.getAnnouncementChannelId()))
|
||||
.ofType(GuildMessageChannel.class)
|
||||
.onErrorResume(ClientException.class, e ->
|
||||
Mono.just(e.getStatus())
|
||||
.filter(HttpResponseStatus.NOT_FOUND::equals)
|
||||
.flatMap(ignored -> DatabaseManager.INSTANCE.deleteAnnouncement(a.getAnnouncementId().toString()))
|
||||
.then(Mono.empty()))
|
||||
.flatMap(chan -> {
|
||||
if (a.getPublish()) {
|
||||
return Messages.sendMessage(men, em, chan)
|
||||
.flatMap(Message::publish)
|
||||
.onErrorResume(e -> Mono.empty());
|
||||
} else
|
||||
return Messages.sendMessage(men, em, chan);
|
||||
})
|
||||
)).then();
|
||||
}
|
||||
|
||||
public static Mono<Void> sendAnnouncementDM(Announcement a, Event event, User user, CalendarData data,
|
||||
GuildSettings settings) {
|
||||
return DisCalClient.getClient().getGuildById(settings.getGuildID())
|
||||
.map(g -> Messages.getMessage("Embed.Announcement.Announce.Dm.Message", "%guild%", g.getName(), settings))
|
||||
.flatMap(msg -> getRealAnnouncementEmbed(a, event, data, settings)
|
||||
.flatMap(em -> Messages.sendDirectMessage(msg, em, user))
|
||||
).then();
|
||||
}
|
||||
|
||||
private static String condensedTime(Announcement a) {
|
||||
return a.getHoursBefore() + "H" + a.getMinutesBefore() + "m";
|
||||
}
|
||||
@@ -448,45 +211,4 @@ public class AnnouncementMessageFormatter {
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private static Mono<String> getSubscriberMentions(Announcement a, Guild guild) {
|
||||
return Mono.defer(() -> {
|
||||
Mono<List<String>> userMentions = Flux.fromIterable(a.getSubscriberUserIds())
|
||||
.flatMap(s -> UserUtils.getUserFromID(s, guild))
|
||||
.map(Member::getNicknameMention)
|
||||
.onErrorReturn("")
|
||||
.collectList()
|
||||
.defaultIfEmpty(new ArrayList<>());
|
||||
|
||||
Mono<List<String>> roleMentions = Flux.fromIterable(a.getSubscriberRoleIds())
|
||||
.flatMap(s -> {
|
||||
if ("everyone".equalsIgnoreCase(s))
|
||||
return Mono.just("@everyone");
|
||||
else if ("here".equalsIgnoreCase(s))
|
||||
return Mono.just("@here");
|
||||
else {
|
||||
return RoleUtils.getRoleFromID(s, guild)
|
||||
.map(Role::getMention)
|
||||
.onErrorReturn("");
|
||||
}
|
||||
}).collectList()
|
||||
.defaultIfEmpty(new ArrayList<>());
|
||||
|
||||
return Mono.zip(userMentions, roleMentions).map(TupleUtils.function((users, roles) -> {
|
||||
StringBuilder mentions = new StringBuilder();
|
||||
|
||||
mentions.append("Subscribers: ");
|
||||
|
||||
for (String s : users) {
|
||||
mentions.append(s).append(" ");
|
||||
}
|
||||
|
||||
for (String s : roles) {
|
||||
mentions.append(s).append(" ");
|
||||
}
|
||||
|
||||
return mentions.toString();
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
package org.dreamexposure.discal.client.module.announcement;
|
||||
|
||||
import com.google.api.services.calendar.Calendar;
|
||||
import com.google.api.services.calendar.model.Event;
|
||||
import discord4j.common.util.Snowflake;
|
||||
import discord4j.core.GatewayDiscordClient;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import org.dreamexposure.discal.client.message.AnnouncementMessageFormatter;
|
||||
import org.dreamexposure.discal.core.database.DatabaseManager;
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType;
|
||||
import org.dreamexposure.discal.core.enums.event.EventColor;
|
||||
import org.dreamexposure.discal.core.object.GuildSettings;
|
||||
import org.dreamexposure.discal.core.object.announcement.Announcement;
|
||||
import org.dreamexposure.discal.core.object.calendar.CalendarData;
|
||||
import org.dreamexposure.discal.core.wrapper.google.EventWrapper;
|
||||
import org.dreamexposure.discal.core.wrapper.google.GoogleAuthWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.function.TupleUtils;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.dreamexposure.discal.core.utils.GlobalVal.getDEFAULT;
|
||||
|
||||
public class AnnouncementThread {
|
||||
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final GatewayDiscordClient client;
|
||||
|
||||
private final Map<Snowflake, Mono<GuildSettings>> allSettings = new ConcurrentHashMap<>();
|
||||
private final Map<Snowflake, Mono<CalendarData>> calendars = new ConcurrentHashMap<>();
|
||||
private final Map<Snowflake, Mono<Calendar>> customServices = new ConcurrentHashMap<>();
|
||||
private final Map<Snowflake, Mono<List<Event>>> allEvents = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<Integer, Mono<Calendar>> discalServices = new ConcurrentHashMap<>();
|
||||
|
||||
private final long maxDifferenceMs = Duration.ofMinutes(5).toMillis();
|
||||
|
||||
public AnnouncementThread(GatewayDiscordClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public Mono<Void> run() {
|
||||
//Get the credentials and cache them
|
||||
Mono<Void> getCredsMono = GoogleAuthWrapper.INSTANCE.credentialsCount()
|
||||
.flatMapMany(i -> Flux.range(0, i))
|
||||
.map(index -> {
|
||||
this.discalServices.put(index, GoogleAuthWrapper.INSTANCE.getCalendarService(index).cache());
|
||||
return index;
|
||||
}).then();
|
||||
|
||||
//Actually do announcements
|
||||
Mono<Void> doAnnMono = this.client.getGuilds()
|
||||
.flatMap(guild -> DatabaseManager.INSTANCE.getEnabledAnnouncements(guild.getId())
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.flatMap(a -> {
|
||||
|
||||
final Mono<GuildSettings> s = this.getSettings(a).cache();
|
||||
final Mono<CalendarData> cd = this.getCalendarData(a).cache();
|
||||
final Mono<Calendar> se = cd.flatMap(calData -> s.flatMap(gs -> this.getService(calData)));
|
||||
|
||||
return Mono.zip(s, cd, se)
|
||||
.flatMap(TupleUtils.function((settings, calData, service) -> {
|
||||
switch (a.getModifier()) {
|
||||
case BEFORE:
|
||||
return this.handleBeforeModifier(guild, a, settings, calData, service);
|
||||
case DURING:
|
||||
return this.handleDuringModifier(guild, a, settings, calData, service);
|
||||
case END:
|
||||
return this.handleEndModifier(guild, a, settings, calData, service);
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
}));
|
||||
})
|
||||
.doOnError(e -> LOGGER.error(getDEFAULT(), "Announcement error", e))
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
)
|
||||
.doOnError(e -> LOGGER.error(getDEFAULT(), "Announcement error", e))
|
||||
.onErrorResume(e -> Mono.empty())
|
||||
.doFinally(ignore -> {
|
||||
this.allSettings.clear();
|
||||
this.calendars.clear();
|
||||
this.customServices.clear();
|
||||
this.allEvents.clear();
|
||||
}).then();
|
||||
|
||||
//Finally execute those two chains, in order.
|
||||
return getCredsMono.then(doAnnMono);
|
||||
}
|
||||
|
||||
//Modifier handling
|
||||
private Mono<Void> handleBeforeModifier(Guild guild, Announcement a, GuildSettings settings, CalendarData calData,
|
||||
Calendar service) {
|
||||
switch (a.getType()) {
|
||||
case SPECIFIC:
|
||||
return EventWrapper.INSTANCE.getEvent(calData, a.getEventId())
|
||||
.switchIfEmpty(DatabaseManager.INSTANCE.deleteAnnouncement(a.getAnnouncementId().toString())
|
||||
.then(Mono.empty())
|
||||
).flatMap(e -> this.inRangeSpecific(a, e)
|
||||
.flatMap(inRange -> {
|
||||
if (inRange) {
|
||||
return AnnouncementMessageFormatter
|
||||
.sendAnnouncementMessage(guild, a, e, calData, settings)
|
||||
.then(DatabaseManager
|
||||
.INSTANCE.deleteAnnouncement(a.getAnnouncementId().toString())
|
||||
);
|
||||
} else {
|
||||
return Mono.empty(); //Not in range, but still valid.
|
||||
}
|
||||
}))
|
||||
.then();
|
||||
case UNIVERSAL:
|
||||
return this.getEvents(calData, service)
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.filter(e -> this.isInRange(a, e))
|
||||
.flatMap(e -> AnnouncementMessageFormatter
|
||||
.sendAnnouncementMessage(guild, a, e, calData, settings))
|
||||
.then();
|
||||
case COLOR:
|
||||
return this.getEvents(calData, service)
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.filter(e -> e.getColorId() != null
|
||||
&& a.getEventColor().equals(EventColor
|
||||
.Companion.fromNameOrHexOrId(e.getColorId())))
|
||||
.filter(e -> this.isInRange(a, e))
|
||||
.flatMap(e -> AnnouncementMessageFormatter
|
||||
.sendAnnouncementMessage(guild, a, e, calData, settings))
|
||||
.then();
|
||||
|
||||
case RECUR:
|
||||
return this.getEvents(calData, service)
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.filter(e -> e.getId().contains("_") && e.getId().split("_")[0].equals(a.getEventId()))
|
||||
.filter(e -> this.isInRange(a, e))
|
||||
.flatMap(e -> AnnouncementMessageFormatter
|
||||
.sendAnnouncementMessage(guild, a, e, calData, settings))
|
||||
.then();
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Actually support this.
|
||||
private Mono<Void> handleDuringModifier(Guild guild, Announcement a, GuildSettings settings, CalendarData calData,
|
||||
Calendar service) {
|
||||
switch (a.getType()) {
|
||||
case SPECIFIC:
|
||||
case UNIVERSAL:
|
||||
case COLOR:
|
||||
case RECUR:
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Actually support this too
|
||||
private Mono<Void> handleEndModifier(Guild guild, Announcement a, GuildSettings settings, CalendarData calData,
|
||||
Calendar service) {
|
||||
switch (a.getType()) {
|
||||
case SPECIFIC:
|
||||
case UNIVERSAL:
|
||||
case COLOR:
|
||||
case RECUR:
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Utility
|
||||
private Mono<Boolean> inRangeSpecific(Announcement a, Event e) {
|
||||
return Mono.defer(() -> {
|
||||
long announcementTimeMs = Integer.toUnsignedLong(a.getMinutesBefore() + (a.getHoursBefore() * 60)) * 60 * 1000;
|
||||
long timeUntilEvent = this.getEventStartMs(e) - System.currentTimeMillis();
|
||||
|
||||
long difference = timeUntilEvent - announcementTimeMs;
|
||||
|
||||
if (difference < 0) {
|
||||
//Event past, we can delete announcement depending on the type
|
||||
if (a.getType() == AnnouncementType.SPECIFIC)
|
||||
return DatabaseManager.INSTANCE.deleteAnnouncement(a.getAnnouncementId().toString())
|
||||
.thenReturn(false);
|
||||
|
||||
return Mono.just(false);
|
||||
} else {
|
||||
return Mono.just(difference <= this.maxDifferenceMs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isInRange(Announcement a, Event e) {
|
||||
long announcementTimeMs = Integer.toUnsignedLong(a.getMinutesBefore() + (a.getHoursBefore() * 60)) * 60 * 1000;
|
||||
long timeUntilEvent = this.getEventStartMs(e) - System.currentTimeMillis();
|
||||
|
||||
long difference = timeUntilEvent - announcementTimeMs;
|
||||
|
||||
if (difference < 0) {
|
||||
//Event past, we can delete announcement depending on the type
|
||||
if (a.getType() == AnnouncementType.SPECIFIC)
|
||||
return false; //Shouldn't even be used for specific types...
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return difference <= this.maxDifferenceMs;
|
||||
}
|
||||
}
|
||||
|
||||
private long getEventStartMs(Event e) {
|
||||
if (e.getStart().getDateTime() != null)
|
||||
return e.getStart().getDateTime().getValue();
|
||||
else
|
||||
return e.getStart().getDate().getValue();
|
||||
|
||||
}
|
||||
|
||||
private Mono<GuildSettings> getSettings(Announcement a) {
|
||||
if (!this.allSettings.containsKey(a.getGuildId()))
|
||||
this.allSettings.put(a.getGuildId(), DatabaseManager.INSTANCE.getSettings(a.getGuildId()).cache());
|
||||
|
||||
return this.allSettings.get(a.getGuildId());
|
||||
}
|
||||
|
||||
//TODO: Allow multiple calendar support
|
||||
private Mono<CalendarData> getCalendarData(Announcement a) {
|
||||
if (!this.calendars.containsKey(a.getGuildId()))
|
||||
this.calendars.put(a.getGuildId(), DatabaseManager.INSTANCE.getMainCalendar(a.getGuildId()).cache());
|
||||
|
||||
return this.calendars.get(a.getGuildId());
|
||||
}
|
||||
|
||||
//TODO: Just redo like literally everything
|
||||
private Mono<Calendar> getService(CalendarData cd) {
|
||||
if (cd.getExternal()) {
|
||||
if (!this.customServices.containsKey(cd.getGuildId()))
|
||||
this.customServices.put(cd.getGuildId(), GoogleAuthWrapper.INSTANCE.getCalendarService(cd).cache());
|
||||
|
||||
return this.customServices.get(cd.getGuildId());
|
||||
}
|
||||
return GoogleAuthWrapper.INSTANCE.getCalendarService(cd.getCredentialId());
|
||||
}
|
||||
|
||||
private Mono<List<Event>> getEvents(CalendarData cd, Calendar service) {
|
||||
if (!this.allEvents.containsKey(cd.getGuildId())) {
|
||||
Mono<List<Event>> events = EventWrapper.INSTANCE.getEvents(cd, service, 15, System.currentTimeMillis()).cache();
|
||||
this.allEvents.put(cd.getGuildId(), events);
|
||||
}
|
||||
return this.allEvents.get(cd.getGuildId());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package org.dreamexposure.discal.client.module.announcement;
|
||||
@@ -97,7 +97,6 @@ public class AnnouncementCommand implements Command {
|
||||
info.getSubCommands().put("info", "Sets an additional info.");
|
||||
info.getSubCommands().put("enable", "Enables or Disables the announcement (alias for `disable`)");
|
||||
info.getSubCommands().put("disable", "Enables or Disables the announcement (alias for `enable`)");
|
||||
info.getSubCommands().put("infoOnly", "Allows for setting an announcement to ONLY display the 'extra info'");
|
||||
info.getSubCommands().put("publish", "Allows for the event to be published if posted in a news channel");
|
||||
|
||||
return info;
|
||||
@@ -174,8 +173,6 @@ public class AnnouncementCommand implements Command {
|
||||
case "disable":
|
||||
case "disabled":
|
||||
return this.moduleEnable(args, event, settings);
|
||||
case "infoonly":
|
||||
return this.moduleInfoOnly(args, event, settings);
|
||||
case "channel":
|
||||
return this.moduleChannel(args, event, settings);
|
||||
case "color":
|
||||
@@ -574,7 +571,7 @@ public class AnnouncementCommand implements Command {
|
||||
+ Messages.getMessage("Embed.Announcement.Subscribe.Roles", "%roles%",
|
||||
subRoleString, settings))
|
||||
.footer(Messages.getMessage("Embed.Announcement.Subscribe.Footer", "%id%",
|
||||
a.getAnnouncementId().toString(), settings), null)
|
||||
a.getId().toString(), settings), null)
|
||||
.build();
|
||||
|
||||
return DatabaseManager.INSTANCE.updateAnnouncement(a).thenReturn(embed);
|
||||
@@ -635,7 +632,7 @@ public class AnnouncementCommand implements Command {
|
||||
+ Messages.getMessage("Embed.Announcement.Subscribe.Roles", "%roles%",
|
||||
subRoleString, settings))
|
||||
.footer(Messages.getMessage("Embed.Announcement.Subscribe.Footer", "%id%",
|
||||
a.getAnnouncementId().toString(), settings), null)
|
||||
a.getId().toString(), settings), null)
|
||||
.build();
|
||||
|
||||
return Mono.when(deleteUserMessage, deleteCreatorMessage).thenReturn(embed);
|
||||
@@ -840,7 +837,7 @@ public class AnnouncementCommand implements Command {
|
||||
+ Messages.getMessage("Embed.Announcement.Unsubscribe.Roles", "%roles%",
|
||||
subRoleString, settings))
|
||||
.footer(Messages.getMessage("Embed.Announcement.Unsubscribe.Footer", "%id%",
|
||||
a.getAnnouncementId().toString(), settings), null)
|
||||
a.getId().toString(), settings), null)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -902,7 +899,7 @@ public class AnnouncementCommand implements Command {
|
||||
+ Messages.getMessage("Embed.Announcement.Unsubscribe.Roles", "%roles%",
|
||||
subRoleString, settings))
|
||||
.footer(Messages.getMessage("Embed.Announcement.Unsubscribe.Footer", "%id%",
|
||||
a.getAnnouncementId().toString(), settings), null)
|
||||
a.getId().toString(), settings), null)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -1245,41 +1242,6 @@ public class AnnouncementCommand implements Command {
|
||||
}).then();
|
||||
}
|
||||
|
||||
private Mono<Void> moduleInfoOnly(String[] args, MessageCreateEvent event, GuildSettings settings) {
|
||||
return Mono.defer(() -> {
|
||||
if (AnnouncementCreator.getCreator().hasAnnouncement(settings.getGuildID())) {
|
||||
Announcement a = AnnouncementCreator.getCreator().getAnnouncement(settings.getGuildID());
|
||||
|
||||
Mono<Void> deleteUserMessage = Messages.deleteMessage(event);
|
||||
Mono<Void> deleteCreatorMessage = Messages.deleteMessage(a.getCreatorMessage());
|
||||
|
||||
return Mono.when(deleteUserMessage, deleteCreatorMessage)
|
||||
.then(AnnouncementMessageFormatter.getFormatAnnouncementEmbed(a, settings))
|
||||
.flatMap(em -> Messages.sendMessage(
|
||||
Messages.getMessage("Announcement.InfoOnly.Creator", settings), em, event))
|
||||
.doOnNext(a::setCreatorMessage);
|
||||
} else if (args.length == 2) {
|
||||
return AnnouncementUtils.announcementExists(args[1], settings.getGuildID()).flatMap(exists -> {
|
||||
if (exists) {
|
||||
UUID id = UUID.fromString(args[1]);
|
||||
AtomicBoolean io = new AtomicBoolean(false); //This has got to be tested...
|
||||
return DatabaseManager.INSTANCE.getAnnouncement(id, settings.getGuildID())
|
||||
.doOnNext(a -> a.setInfoOnly(!a.getInfoOnly()))
|
||||
.doOnNext(a -> io.set(a.getInfoOnly()))
|
||||
.flatMap(DatabaseManager.INSTANCE::updateAnnouncement)
|
||||
.map(i -> Messages.getMessage("Announcement.InfoOnly.Success", "%value%", io.get() + "", settings))
|
||||
.flatMap(msg -> Messages.sendMessage(msg, event));
|
||||
} else {
|
||||
return Messages.sendMessage(
|
||||
Messages.getMessage("Creator.Announcement.CannotFind.Announcement", settings), event);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Messages.sendMessage(Messages.getMessage("Announcement.InfoOnly.Specify", settings), event);
|
||||
}
|
||||
}).then();
|
||||
}
|
||||
|
||||
private Mono<Void> modulePublish(MessageCreateEvent event, GuildSettings settings) {
|
||||
return Mono.defer(() -> {
|
||||
if (AnnouncementCreator.getCreator().hasAnnouncement(settings.getGuildID())) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import io.lettuce.core.RedisURI
|
||||
import org.dreamexposure.discal.Application
|
||||
import org.dreamexposure.discal.client.listeners.discord.*
|
||||
import org.dreamexposure.discal.client.message.Messages
|
||||
import org.dreamexposure.discal.client.module.announcement.AnnouncementThread
|
||||
import org.dreamexposure.discal.client.module.command.*
|
||||
import org.dreamexposure.discal.client.service.TimeManager
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
@@ -34,10 +33,8 @@ import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal.STATUS
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.io.FileReader
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import javax.annotation.PreDestroy
|
||||
import kotlin.system.exitProcess
|
||||
@@ -112,15 +109,7 @@ class DisCalClient {
|
||||
.on(ChatInputInteractionEvent::class.java, slashCommandListener::handle)
|
||||
.then()
|
||||
|
||||
val startAnnouncement = Flux.interval(Duration.ofMinutes(5))
|
||||
.onBackpressureBuffer()
|
||||
.flatMap {
|
||||
AnnouncementThread(client).run().doOnError {
|
||||
LOGGER.error("Announcement error", it)
|
||||
}.onErrorResume { Mono.empty() }
|
||||
}
|
||||
|
||||
Mono.`when`(onReady, onRoleDelete, onCommand, onSlashCommand, startAnnouncement)
|
||||
Mono.`when`(onReady, onRoleDelete, onCommand, onSlashCommand)
|
||||
}.block()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import discord4j.core.`object`.entity.channel.GuildChannel
|
||||
import discord4j.core.spec.EmbedCreateSpec
|
||||
import org.dreamexposure.discal.core.`object`.announcement.Announcement
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementStyle
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType
|
||||
import org.dreamexposure.discal.core.extensions.asDiscordTimestamp
|
||||
import org.dreamexposure.discal.core.extensions.discord4j.getSettings
|
||||
@@ -14,6 +15,16 @@ import reactor.core.publisher.Mono
|
||||
import reactor.function.TupleUtils
|
||||
|
||||
object AnnouncementEmbed : EmbedMaker {
|
||||
fun determine(ann: Announcement, event: Event, guild: Guild): Mono<EmbedCreateSpec> {
|
||||
return guild.getSettings().flatMap { settings ->
|
||||
when (settings.announcementStyle) {
|
||||
AnnouncementStyle.FULL -> full(ann, event, guild)
|
||||
AnnouncementStyle.SIMPLE -> simple(ann, event, guild)
|
||||
AnnouncementStyle.EVENT -> event(ann, event, guild)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun full(ann: Announcement, event: Event, guild: Guild): Mono<EmbedCreateSpec> {
|
||||
return guild.getSettings().map { settings ->
|
||||
val builder = defaultBuilder(guild, settings)
|
||||
@@ -52,7 +63,7 @@ object AnnouncementEmbed : EmbedMaker {
|
||||
builder.image(event.image)
|
||||
}
|
||||
|
||||
builder.footer(getMessage("announcement", "full.footer", settings, ann.announcementId.toString()), null)
|
||||
builder.footer(getMessage("announcement", "full.footer", settings, ann.id.toString()), null)
|
||||
|
||||
builder.build()
|
||||
}
|
||||
@@ -84,7 +95,7 @@ object AnnouncementEmbed : EmbedMaker {
|
||||
builder.image(event.image)
|
||||
}
|
||||
|
||||
builder.footer(getMessage("announcement", "simple.footer", settings, ann.announcementId.toString()), null)
|
||||
builder.footer(getMessage("announcement", "simple.footer", settings, ann.id.toString()), null)
|
||||
|
||||
builder.build()
|
||||
}
|
||||
@@ -127,7 +138,7 @@ object AnnouncementEmbed : EmbedMaker {
|
||||
builder.image(event.image)
|
||||
}
|
||||
|
||||
builder.footer(getMessage("announcement", "event.footer", settings, ann.announcementId.toString()), null)
|
||||
builder.footer(getMessage("announcement", "event.footer", settings, ann.id.toString()), null)
|
||||
|
||||
builder.build()
|
||||
}
|
||||
@@ -137,7 +148,7 @@ object AnnouncementEmbed : EmbedMaker {
|
||||
return guild.getSettings().map { settings ->
|
||||
val builder = defaultBuilder(guild, settings)
|
||||
.title(getMessage("announcement", "con.title", settings))
|
||||
.addField(getMessage("announcement", "con.field.id", settings), ann.announcementId.toString(), false)
|
||||
.addField(getMessage("announcement", "con.field.id", settings), ann.id.toString(), false)
|
||||
.addField(getMessage("announcement", "con.field.time", settings), condensedTime(ann), true)
|
||||
.addField(getMessage("announcement", "con.field.enabled", settings), "${ann.enabled}", true)
|
||||
.footer(getMessage("announcement", "con.footer", settings, ann.type.name, ann.modifier.name), null)
|
||||
@@ -180,7 +191,7 @@ object AnnouncementEmbed : EmbedMaker {
|
||||
} else
|
||||
builder.color(GlobalVal.discalColor)
|
||||
|
||||
builder.addField(getMessage("announcement", "view.field.id", settings), ann.announcementId.toString(), false)
|
||||
builder.addField(getMessage("announcement", "view.field.id", settings), ann.id.toString(), false)
|
||||
.addField(getMessage("announcement", "view.field.enabled", settings), "${ann.enabled}", true)
|
||||
.addField(getMessage("announcement", "view.field.publish", settings), "${ann.publish}", true)
|
||||
.build()
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
package org.dreamexposure.discal.client.service
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.`object`.entity.Guild
|
||||
import discord4j.core.`object`.entity.Message
|
||||
import discord4j.core.`object`.entity.Role
|
||||
import discord4j.core.`object`.entity.channel.GuildMessageChannel
|
||||
import discord4j.core.spec.MessageCreateSpec
|
||||
import discord4j.rest.http.client.ClientException
|
||||
import io.netty.handler.codec.http.HttpResponseStatus
|
||||
import org.dreamexposure.discal.client.DisCalClient
|
||||
import org.dreamexposure.discal.client.message.embed.AnnouncementEmbed
|
||||
import org.dreamexposure.discal.core.`object`.announcement.Announcement
|
||||
import org.dreamexposure.discal.core.`object`.announcement.AnnouncementCache
|
||||
import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementModifier
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementType.*
|
||||
import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LOGGER
|
||||
import org.dreamexposure.discal.core.utils.GlobalVal
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.function.TupleUtils
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Component
|
||||
class AnnouncementService : ApplicationRunner {
|
||||
private val maxDifferenceMs = Duration.ofMinutes(5).toMillis()
|
||||
|
||||
private val cached = ConcurrentHashMap<Snowflake, AnnouncementCache>()
|
||||
|
||||
// Start
|
||||
override fun run(args: ApplicationArguments?) {
|
||||
Flux.interval(Duration.ofMinutes(5))
|
||||
.onBackpressureBuffer()
|
||||
.flatMap { doAnnouncementCycle() }
|
||||
.doOnError { LOGGER.error(GlobalVal.DEFAULT, "!-Announcement run error-!", it) }
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
// Runner
|
||||
private fun doAnnouncementCycle(): Mono<Void> {
|
||||
//TODO: This should come in through DI once other legacy is removed/rewritten
|
||||
if (DisCalClient.client == null) return Mono.empty()
|
||||
|
||||
return DisCalClient.client!!.guilds.flatMap { guild ->
|
||||
DatabaseManager.getEnabledAnnouncements(guild.id)
|
||||
.flatMapMany { Flux.fromIterable(it) }
|
||||
.flatMap { announcement ->
|
||||
when (announcement.modifier) {
|
||||
AnnouncementModifier.BEFORE -> handleBeforeModifier(guild, announcement)
|
||||
AnnouncementModifier.DURING -> handleDuringModifier(guild, announcement)
|
||||
AnnouncementModifier.END -> handleEndModifier(guild, announcement)
|
||||
}
|
||||
}.doOnError {
|
||||
LOGGER.error(GlobalVal.DEFAULT, "Announcement error", it)
|
||||
}.onErrorResume { Mono.empty() }
|
||||
}.doOnError {
|
||||
LOGGER.error(GlobalVal.DEFAULT, "Announcement error", it)
|
||||
}.onErrorResume {
|
||||
Mono.empty()
|
||||
}.doFinally {
|
||||
cached.clear()
|
||||
}.then()
|
||||
}
|
||||
|
||||
// Modifier handling
|
||||
private fun handleBeforeModifier(guild: Guild, announcement: Announcement): Mono<Void> {
|
||||
when (announcement.type) {
|
||||
SPECIFIC -> {
|
||||
return getCalendar(guild, announcement)
|
||||
.flatMap { it.getEvent(announcement.eventId) }
|
||||
//Event announcement is tied to was deleted
|
||||
.switchIfEmpty(DatabaseManager.deleteAnnouncement(announcement.id.toString()).then(Mono.empty()))
|
||||
.filterWhen { isInRange(announcement, it) }
|
||||
.flatMap { sendAnnouncement(guild, announcement, it) }
|
||||
// Delete specific announcement after posted
|
||||
.flatMap { DatabaseManager.deleteAnnouncement(announcement.id.toString()) }
|
||||
.then()
|
||||
}
|
||||
UNIVERSAL -> {
|
||||
return getEvents(guild, announcement)
|
||||
.filterWhen { isInRange(announcement, it) }
|
||||
.flatMap { sendAnnouncement(guild, announcement, it) }
|
||||
.then()
|
||||
}
|
||||
COLOR -> {
|
||||
return getEvents(guild, announcement)
|
||||
.filter { it.color == announcement.eventColor }
|
||||
.filterWhen { isInRange(announcement, it) }
|
||||
.flatMap { sendAnnouncement(guild, announcement, it) }
|
||||
.then()
|
||||
}
|
||||
RECUR -> {
|
||||
return getEvents(guild, announcement)
|
||||
.filter { it.eventId.contains("_") && it.eventId.split("_")[0] == announcement.eventId }
|
||||
.filterWhen { isInRange(announcement, it) }
|
||||
.flatMap { sendAnnouncement(guild, announcement, it) }
|
||||
.then()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun handleDuringModifier(guild: Guild, announcement: Announcement): Mono<Void> {
|
||||
//TODO: Not yet implemented
|
||||
|
||||
return Mono.empty()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun handleEndModifier(guild: Guild, announcement: Announcement): Mono<Void> {
|
||||
//TODO: Not yet implemented
|
||||
|
||||
return Mono.empty()
|
||||
}
|
||||
|
||||
// Utility
|
||||
private fun isInRange(announcement: Announcement, event: Event): Mono<Boolean> {
|
||||
val announcementTime = Duration
|
||||
.ofHours(announcement.hoursBefore.toLong())
|
||||
.plusMinutes(announcement.minutesBefore.toLong())
|
||||
.toMillis()
|
||||
val timeUntilEvent = event.start.minusMillis(System.currentTimeMillis()).toEpochMilli()
|
||||
|
||||
val difference = timeUntilEvent - announcementTime
|
||||
|
||||
if (difference < 0) {
|
||||
//event past, delete if specific type
|
||||
if (announcement.type == SPECIFIC) {
|
||||
return DatabaseManager.deleteAnnouncement(announcement.id.toString())
|
||||
.thenReturn(false)
|
||||
}
|
||||
return Mono.just(false)
|
||||
} else return Mono.just(difference <= maxDifferenceMs)
|
||||
}
|
||||
|
||||
private fun sendAnnouncement(guild: Guild, announcement: Announcement, event: Event): Mono<Message> {
|
||||
val embedMono = AnnouncementEmbed.determine(announcement, event, guild)
|
||||
val mentionsMono = buildMentions(guild, announcement).onErrorReturn("")
|
||||
|
||||
return guild.getChannelById(Snowflake.of(announcement.announcementChannelId))
|
||||
.ofType(GuildMessageChannel::class.java)
|
||||
.flatMap { channel ->
|
||||
Mono.zip(embedMono, mentionsMono).flatMap(TupleUtils.function { embed, mentions ->
|
||||
if (mentions.isEmpty())
|
||||
return@function channel.createMessage(embed)
|
||||
else
|
||||
return@function channel.createMessage(
|
||||
MessageCreateSpec.builder()
|
||||
.content(mentions)
|
||||
.addEmbed(embed)
|
||||
.build()
|
||||
)
|
||||
}).flatMap { message ->
|
||||
if (announcement.publish) {
|
||||
message.publish()
|
||||
} else Mono.just(message)
|
||||
}
|
||||
}.onErrorResume(ClientException::class.java) {
|
||||
Mono.just(it)
|
||||
.filter(HttpResponseStatus.NOT_FOUND::equals)
|
||||
// Channel announcement should post to was deleted
|
||||
.flatMap { DatabaseManager.deleteAnnouncement(announcement.id.toString()) }
|
||||
.then(Mono.empty())
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMentions(guild: Guild, announcement: Announcement): Mono<String> {
|
||||
val userMentions = Flux.fromIterable(announcement.subscriberUserIds)
|
||||
.flatMap { guild.getMemberById(Snowflake.of(it)) }
|
||||
.map { it.nicknameMention }
|
||||
.onErrorReturn("")
|
||||
.collectList()
|
||||
.defaultIfEmpty(listOf())
|
||||
|
||||
val roleMentions = Flux.fromIterable(announcement.subscriberRoleIds)
|
||||
.flatMap {
|
||||
if (it.equals("everyone", true)) guild.everyoneRole.map(Role::getMention)
|
||||
else if (it.equals("here", true)) Mono.just("here")
|
||||
else guild.getRoleById(Snowflake.of(it)).map(Role::getMention)
|
||||
}
|
||||
.onErrorReturn("")
|
||||
.collectList()
|
||||
.defaultIfEmpty(listOf())
|
||||
|
||||
return Mono.zip(userMentions, roleMentions).map(TupleUtils.function { users, roles ->
|
||||
if (users.isEmpty() && roles.isEmpty()) ""
|
||||
else {
|
||||
val mentions = StringBuilder()
|
||||
|
||||
mentions.append("Subscribers: ")
|
||||
|
||||
for (u in users) mentions.append("$u ")
|
||||
for (r in roles) mentions.append("$r ")
|
||||
|
||||
mentions.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Cache things
|
||||
private fun getCalendar(guild: Guild, announcement: Announcement): Mono<Calendar> {
|
||||
val cached = getCached(announcement.guildId)
|
||||
|
||||
return if (!cached.calendars.contains(announcement.calendarNumber)) {
|
||||
guild.getCalendar(announcement.calendarNumber)
|
||||
.doOnNext { cached.calendars[it.calendarNumber] = it }
|
||||
} else Mono.justOrEmpty(cached.calendars[announcement.calendarNumber])
|
||||
}
|
||||
|
||||
private fun getEvents(guild: Guild, announcement: Announcement): Flux<Event> {
|
||||
val cached = getCached(announcement.guildId)
|
||||
|
||||
return if (!cached.events.contains(announcement.calendarNumber)) {
|
||||
getCalendar(guild, announcement).flatMapMany {
|
||||
it.getUpcomingEvents(20).cache()
|
||||
}
|
||||
} else cached.events[announcement.calendarNumber]!!
|
||||
}
|
||||
|
||||
private fun getCached(guildId: Snowflake): AnnouncementCache {
|
||||
if (!cached.contains(guildId))
|
||||
cached[guildId] = AnnouncementCache(guildId)
|
||||
|
||||
return cached[guildId]!!
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,10 @@ import discord4j.common.util.Snowflake;
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Role;
|
||||
import discord4j.discordjson.json.GuildUpdateData;
|
||||
import discord4j.discordjson.json.MemberData;
|
||||
import discord4j.discordjson.json.RoleData;
|
||||
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
|
||||
@@ -49,64 +39,6 @@ public class PermissionChecker {
|
||||
});
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasDisCalRole(final Member member, final GuildSettings settings) {
|
||||
if ("everyone".equalsIgnoreCase(settings.getControlRole()))
|
||||
return Mono.just(true);
|
||||
if (Snowflake.of(settings.getControlRole()).equals(settings.getGuildID())) //also everyone
|
||||
return Mono.just(true);
|
||||
|
||||
//User doesn't need bot control role if they have admin permissions.
|
||||
final Mono<Boolean> hasAdmin = Mono.just(member).flatMap(Member::getBasePermissions).map(perms ->
|
||||
perms.contains(Permission.ADMINISTRATOR) || perms.contains(Permission.MANAGE_GUILD));
|
||||
|
||||
return hasAdmin.flatMap(has -> {
|
||||
if (has) {
|
||||
return Mono.just(true);
|
||||
} else {
|
||||
return Mono.just(member).flatMapMany(Member::getRoles)
|
||||
.map(Role::getId)
|
||||
.any(id -> id.equals(Snowflake.of(settings.getControlRole())));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Mono<Boolean> hasSufficientRole(final MessageCreateEvent event, final GuildSettings settings) {
|
||||
if ("everyone".equalsIgnoreCase(settings.getControlRole()))
|
||||
return Mono.just(true);
|
||||
if (Snowflake.of(settings.getControlRole()).equals(settings.getGuildID())) //also everyone
|
||||
return Mono.just(true);
|
||||
|
||||
return Mono.justOrEmpty(event.getMember())
|
||||
.flatMapMany(Member::getRoles)
|
||||
.map(Role::getId)
|
||||
.any(snowflake -> snowflake.equals(Snowflake.of(settings.getControlRole())));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Mono<Boolean> hasSufficientRole(final Member member, final GuildSettings settings) {
|
||||
if ("everyone".equalsIgnoreCase(settings.getControlRole()))
|
||||
return Mono.just(true);
|
||||
if (Snowflake.of(settings.getControlRole()).equals(settings.getGuildID())) //also everyone
|
||||
return Mono.just(true);
|
||||
|
||||
return Mono.from(member.getRoles()
|
||||
.map(Role::getId)
|
||||
.any(snowflake -> snowflake.equals(Snowflake.of(settings.getControlRole())))
|
||||
);
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasSufficientRole(final RestMember member, final GuildSettings settings) {
|
||||
if ("everyone".equalsIgnoreCase(settings.getControlRole()))
|
||||
return Mono.just(true);
|
||||
if (Snowflake.of(settings.getControlRole()).equals(settings.getGuildID())) //also everyone
|
||||
return Mono.just(true);
|
||||
|
||||
return member.getData()
|
||||
.map(MemberData::roles)
|
||||
.map(roles -> roles.contains(settings.getControlRole()));
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasManageServerRole(final MessageCreateEvent event) {
|
||||
return Mono.justOrEmpty(event.getMember())
|
||||
.flatMap(Member::getBasePermissions)
|
||||
@@ -114,38 +46,4 @@ public class PermissionChecker {
|
||||
|| perms.contains(Permission.ADMINISTRATOR))
|
||||
.defaultIfEmpty(false);
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasManageServerRole(final Member m) {
|
||||
return m.getBasePermissions()
|
||||
.map(perms -> perms.contains(Permission.MANAGE_GUILD)
|
||||
|| perms.contains(Permission.ADMINISTRATOR)
|
||||
);
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasManageServerRole(final RestMember m, final RestGuild g) {
|
||||
return hasPermissions(m, g, permissions ->
|
||||
permissions.contains(Permission.MANAGE_GUILD)
|
||||
|| permissions.contains(Permission.ADMINISTRATOR));
|
||||
}
|
||||
|
||||
public static Mono<Boolean> hasPermissions(final RestMember m, final RestGuild g,
|
||||
final Predicate<PermissionSet> pred) {
|
||||
return m.getData().flatMap(memberData ->
|
||||
g.getData().map(GuildUpdateData::roles)
|
||||
.flatMapMany(Flux::fromIterable)
|
||||
.filter(roleData -> memberData.roles().contains(roleData.id()))
|
||||
.map(RoleData::permissions)
|
||||
.reduce(0L, (perm, accumulator) -> accumulator | perm)
|
||||
.map(PermissionSet::of)
|
||||
.map(pred::test)
|
||||
);
|
||||
}
|
||||
|
||||
public static Mono<Boolean> botHasMessageManagePerms(final MessageCreateEvent event) {
|
||||
return event.getGuild()
|
||||
.flatMap(guild -> guild.getMemberById(Snowflake.of(BotSettings.ID.get()))
|
||||
.flatMap(Member::getBasePermissions)
|
||||
.map(perms -> perms.contains(Permission.MANAGE_MESSAGES))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ object DatabaseManager {
|
||||
val query = "SELECT * FROM ${Tables.ANNOUNCEMENTS.table} WHERE ANNOUNCEMENT_ID = ?"
|
||||
|
||||
Mono.from(c.createStatement(query)
|
||||
.bind(0, announcement.announcementId.toString())
|
||||
.bind(0, announcement.id.toString())
|
||||
.execute()
|
||||
).flatMapMany { res ->
|
||||
res.map { row, _ -> row }
|
||||
@@ -259,7 +259,7 @@ object DatabaseManager {
|
||||
CALENDAR_NUMBER = ?, SUBSCRIBERS_ROLE = ?, SUBSCRIBERS_USER = ?, CHANNEL_ID = ?,
|
||||
ANNOUNCEMENT_TYPE = ?, MODIFIER = ?, EVENT_ID = ?, EVENT_COLOR = ?,
|
||||
HOURS_BEFORE = ?, MINUTES_BEFORE = ?,
|
||||
INFO = ?, ENABLED = ?, INFO_ONLY = ?, PUBLISH = ?
|
||||
INFO = ?, ENABLED = ?, PUBLISH = ?
|
||||
WHERE ANNOUNCEMENT_ID = ?
|
||||
""".trimMargin()
|
||||
|
||||
@@ -276,9 +276,8 @@ object DatabaseManager {
|
||||
.bind(9, announcement.minutesBefore)
|
||||
.bind(10, announcement.info)
|
||||
.bind(11, announcement.enabled)
|
||||
.bind(12, announcement.infoOnly)
|
||||
.bind(13, announcement.publish)
|
||||
.bind(14, announcement.announcementId.toString())
|
||||
.bind(12, announcement.publish)
|
||||
.bind(13, announcement.id.toString())
|
||||
.execute()
|
||||
).flatMapMany(Result::getRowsUpdated)
|
||||
.hasElements()
|
||||
@@ -287,12 +286,12 @@ object DatabaseManager {
|
||||
val insertCommand = """INSERT INTO ${Tables.ANNOUNCEMENTS.table}
|
||||
(ANNOUNCEMENT_ID, CALENDAR_NUMBER, GUILD_ID, SUBSCRIBERS_ROLE, SUBSCRIBERS_USER,
|
||||
CHANNEL_ID, ANNOUNCEMENT_TYPE, MODIFIER, EVENT_ID, EVENT_COLOR,
|
||||
HOURS_BEFORE, MINUTES_BEFORE, INFO, ENABLED, INFO_ONLY, PUBLISH)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
HOURS_BEFORE, MINUTES_BEFORE, INFO, ENABLED, PUBLISH)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""".trimMargin()
|
||||
|
||||
Mono.from(c.createStatement(insertCommand)
|
||||
.bind(0, announcement.announcementId.toString())
|
||||
.bind(0, announcement.id.toString())
|
||||
.bind(1, announcement.calendarNumber)
|
||||
.bind(2, announcement.guildId.asString())
|
||||
.bind(3, announcement.subscriberRoleIds.asStringList())
|
||||
@@ -306,8 +305,7 @@ object DatabaseManager {
|
||||
.bind(11, announcement.minutesBefore)
|
||||
.bind(12, announcement.info)
|
||||
.bind(13, announcement.enabled)
|
||||
.bind(14, announcement.infoOnly)
|
||||
.bind(15, announcement.publish)
|
||||
.bind(14, announcement.publish)
|
||||
.execute()
|
||||
).flatMapMany(Result::getRowsUpdated)
|
||||
.hasElements()
|
||||
@@ -761,7 +759,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -799,7 +796,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -838,7 +834,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -876,7 +871,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -915,7 +909,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -953,7 +946,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -991,7 +983,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
@@ -1030,7 +1021,6 @@ object DatabaseManager {
|
||||
a.minutesBefore = row["MINUTES_BEFORE", Int::class.java]!!
|
||||
a.info = row["INFO", String::class.java]!!
|
||||
a.enabled = row["ENABLED", Boolean::class.java]!!
|
||||
a.infoOnly = row["INFO_ONLY", Boolean::class.java]!!
|
||||
a.publish = row["PUBLISH", Boolean::class.java]!!
|
||||
|
||||
a
|
||||
|
||||
@@ -19,8 +19,7 @@ data class Announcement(
|
||||
val guildId: Snowflake,
|
||||
) {
|
||||
@Serializable(with = UUIDasStringSerializer::class)
|
||||
@SerialName("id")
|
||||
var announcementId: UUID = UUID.randomUUID()
|
||||
var id: UUID = UUID.randomUUID()
|
||||
private set
|
||||
|
||||
@SerialName("subscriber_roles")
|
||||
@@ -52,9 +51,6 @@ data class Announcement(
|
||||
|
||||
var enabled = true
|
||||
|
||||
@Deprecated(message = "Info only support is dropping in favor of a guild-wide announcement-style")
|
||||
@SerialName("info_only")
|
||||
var infoOnly = false
|
||||
var publish = false
|
||||
|
||||
//Stuff for wizards
|
||||
@@ -68,14 +64,14 @@ data class Announcement(
|
||||
var lastEdit = System.currentTimeMillis()
|
||||
|
||||
constructor(guildId: Snowflake, announcementId: UUID) : this(guildId) {
|
||||
this.announcementId = announcementId
|
||||
this.id = announcementId
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun copy(from: Announcement, copyId: Boolean = false): Announcement {
|
||||
val to = from.copy()
|
||||
if (copyId)
|
||||
to.announcementId = UUID.randomUUID()
|
||||
to.id = UUID.randomUUID()
|
||||
|
||||
//Copy all the other params...
|
||||
to.subscriberRoleIds.addAll(from.subscriberRoleIds)
|
||||
@@ -89,7 +85,6 @@ data class Announcement(
|
||||
to.minutesBefore = from.minutesBefore
|
||||
to.info = from.info
|
||||
to.enabled = from.enabled
|
||||
to.infoOnly = from.infoOnly
|
||||
to.publish = to.publish
|
||||
|
||||
return to
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.dreamexposure.discal.core.`object`.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
import reactor.core.publisher.Flux
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
data class AnnouncementCache(
|
||||
val id: Snowflake,
|
||||
val calendars: ConcurrentHashMap<Int, Calendar> = ConcurrentHashMap(),
|
||||
val events: ConcurrentHashMap<Int, Flux<Event>> = ConcurrentHashMap(),
|
||||
)
|
||||
@@ -69,7 +69,7 @@ object EventWrapper {
|
||||
}
|
||||
|
||||
fun getEvents(calData: CalendarData, amount: Int, start: Long): Mono<List<Event>> {
|
||||
return GoogleAuthWrapper.getCalendarService(calData).flatMap { service: Calendar ->
|
||||
return GoogleAuthWrapper.getCalendarService(calData).flatMap { service ->
|
||||
Mono.fromCallable {
|
||||
service.events()
|
||||
.list(calData.calendarId)
|
||||
@@ -87,24 +87,6 @@ object EventWrapper {
|
||||
}.onErrorResume { Mono.empty() }
|
||||
}
|
||||
|
||||
@Deprecated(message = "Deprecated, do not use service directly")
|
||||
fun getEvents(calData: CalendarData, service: Calendar, amount: Int, start: Long): Mono<List<Event>> {
|
||||
return Mono.fromCallable {
|
||||
service.events()
|
||||
.list(calData.calendarId)
|
||||
.setMaxResults(amount)
|
||||
.setTimeMin(DateTime(start))
|
||||
.setOrderBy("startTime")
|
||||
.setSingleEvents(true)
|
||||
.setShowDeleted(false)
|
||||
.setQuotaUser(calData.guildId.asString())
|
||||
.execute().items
|
||||
}.subscribeOn(Schedulers.boundedElastic())
|
||||
.doOnError {
|
||||
LOGGER.error(GlobalVal.DEFAULT, "[G.Cal] Event list(2) failure", it)
|
||||
}.onErrorResume { Mono.empty() }
|
||||
}
|
||||
|
||||
fun getEvents(calData: CalendarData, amount: Int, start: Long, end: Long): Mono<List<Event>> {
|
||||
return GoogleAuthWrapper.getCalendarService(calData).flatMap { service: Calendar ->
|
||||
Mono.fromCallable {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE ${prefix}announcements
|
||||
DROP COLUMN INFO_ONLY;
|
||||
@@ -59,7 +59,6 @@ class CreateAnnouncementEndpoint(val client: DiscordClient) {
|
||||
announcement.minutesBefore = body.optInt("minutes", 0)
|
||||
|
||||
announcement.info = body.optString("info", "N/a")
|
||||
announcement.infoOnly = body.optBoolean("info_only", false)
|
||||
|
||||
announcement.publish = body.optBoolean("publish", false)
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ class UpdateAnnouncementEndpoint(val client: DiscordClient) {
|
||||
ann.hoursBefore = body.optInt("hours", ann.hoursBefore)
|
||||
ann.minutesBefore = body.optInt("hours", ann.minutesBefore)
|
||||
ann.info = body.optString("info", ann.info)
|
||||
ann.infoOnly = body.optBoolean("info_only", ann.infoOnly)
|
||||
ann.enabled = body.optBoolean("enabled", ann.enabled)
|
||||
ann.publish = body.optBoolean("publish", ann.publish)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user