use of com.sx4.bot.core.Sx4 in project Sx4 by sx4-discord-bot.
the class ModUtility method performAction.
public static CompletableFuture<? extends Action> performAction(Sx4 bot, Action action, Member target, Member moderator, Reason reason) {
Guild guild = target.getGuild();
switch(action.getModAction()) {
case WARN:
return ModUtility.warn(bot, target, moderator, reason);
case MUTE:
case MUTE_EXTEND:
if (!guild.getSelfMember().hasPermission(Permission.MANAGE_ROLES)) {
return CompletableFuture.failedFuture(new BotPermissionException(Permission.MANAGE_ROLES));
}
return ModUtility.mute(bot, target, moderator, Duration.ofSeconds(((TimeAction) action).getDuration()), action.getModAction().isExtend(), reason);
case KICK:
if (!guild.getSelfMember().hasPermission(Permission.KICK_MEMBERS)) {
return CompletableFuture.failedFuture(new BotPermissionException(Permission.KICK_MEMBERS));
}
if (!guild.getSelfMember().canInteract(target)) {
return CompletableFuture.failedFuture(new BotHierarchyException("kick"));
}
if (!moderator.hasPermission(Permission.KICK_MEMBERS)) {
return CompletableFuture.failedFuture(new AuthorPermissionException(Permission.KICK_MEMBERS));
}
return target.kick(ModUtility.getAuditReason(reason, moderator.getUser())).submit().thenApply($ -> {
bot.getModActionManager().onModAction(new KickEvent(moderator, target.getUser(), reason));
return action;
});
case TEMPORARY_BAN:
if (!guild.getSelfMember().hasPermission(Permission.BAN_MEMBERS)) {
return CompletableFuture.failedFuture(new BotPermissionException(Permission.BAN_MEMBERS));
}
if (!guild.getSelfMember().canInteract(target)) {
return CompletableFuture.failedFuture(new BotHierarchyException("ban"));
}
if (!moderator.hasPermission(Permission.BAN_MEMBERS)) {
return CompletableFuture.failedFuture(new AuthorPermissionException(Permission.BAN_MEMBERS));
}
long temporaryBanDuration = ((TimeAction) action).getDuration();
List<Bson> temporaryBanUpdate = List.of(Operators.set("unbanAt", Operators.add(Operators.nowEpochSecond(), temporaryBanDuration)));
Bson filter = Filters.and(Filters.eq("userId", target.getIdLong()), Filters.eq("guildId", guild.getIdLong()));
return bot.getMongo().updateTemporaryBan(filter, temporaryBanUpdate, new UpdateOptions().upsert(true)).thenCompose(temporaryBanResult -> target.ban(1).reason(ModUtility.getAuditReason(reason, moderator.getUser())).submit()).thenApply($ -> {
bot.getModActionManager().onModAction(new TemporaryBanEvent(moderator, target.getUser(), reason, true, temporaryBanDuration));
bot.getTemporaryBanManager().putBan(guild.getIdLong(), target.getIdLong(), temporaryBanDuration);
return action;
});
case BAN:
if (!guild.getSelfMember().hasPermission(Permission.BAN_MEMBERS)) {
return CompletableFuture.failedFuture(new BotPermissionException(Permission.BAN_MEMBERS));
}
if (!guild.getSelfMember().canInteract(target)) {
return CompletableFuture.failedFuture(new BotHierarchyException("ban"));
}
if (!moderator.hasPermission(Permission.BAN_MEMBERS)) {
return CompletableFuture.failedFuture(new AuthorPermissionException(Permission.BAN_MEMBERS));
}
return target.ban(1).reason(ModUtility.getAuditReason(reason, moderator.getUser())).submit().thenApply($ -> {
bot.getModActionManager().onModAction(new BanEvent(moderator, target.getUser(), reason, true));
return action;
});
default:
return CompletableFuture.completedFuture(null);
}
}
use of com.sx4.bot.core.Sx4 in project Sx4 by sx4-discord-bot.
the class ModUtility method mute.
public static CompletableFuture<TimeAction> mute(Sx4 bot, Member target, Member moderator, Duration time, boolean extend, Reason reason) {
Guild guild = target.getGuild();
long guildId = guild.getIdLong(), userId = target.getIdLong();
Document mute = bot.getMongo().getGuildById(guildId, Projections.include("mute.roleId", "mute.defaultTime", "mute.autoUpdate")).get("mute", MongoDatabase.EMPTY_DOCUMENT);
long duration = time == null ? mute.get("defaultTime", ModUtility.DEFAULT_MUTE_DURATION) : time.toSeconds();
AtomicReference<Role> atomicRole = new AtomicReference<>();
return ModUtility.upsertMuteRole(bot.getMongo(), guild, mute.get("roleId", 0L), mute.get("autoUpdate", true)).thenCompose(role -> {
if (!guild.getSelfMember().hasPermission(Permission.MANAGE_ROLES)) {
throw new BotPermissionException(Permission.MANAGE_ROLES);
}
if (!guild.getSelfMember().canInteract(role)) {
throw new BotHierarchyException("mute");
}
atomicRole.set(role);
List<Bson> update = List.of(Operators.set("unmuteAt", Operators.add(duration, Operators.cond(Operators.and(extend, Operators.exists("$unmuteAt")), "$unmuteAt", Operators.nowEpochSecond()))));
Bson filter = Filters.and(Filters.eq("userId", userId), Filters.eq("guildId", guildId));
return bot.getMongo().updateMute(filter, update, new UpdateOptions().upsert(true));
}).thenCompose(result -> {
Role role = atomicRole.get();
boolean wasExtended = extend && result.getUpsertedId() == null;
return guild.addRoleToMember(target, role).reason(ModUtility.getAuditReason(reason, moderator.getUser())).submit().thenApply($ -> {
bot.getMuteManager().putMute(guild.getIdLong(), target.getIdLong(), role.getIdLong(), duration, wasExtended);
ModActionEvent modEvent = wasExtended ? new MuteExtendEvent(moderator, target.getUser(), reason, duration) : new MuteEvent(moderator, target.getUser(), reason, duration);
bot.getModActionManager().onModAction(modEvent);
return new TimeAction(wasExtended ? ModAction.MUTE_EXTEND : ModAction.MUTE, duration);
});
});
}
use of com.sx4.bot.core.Sx4 in project Sx4 by sx4-discord-bot.
the class ModUtility method warn.
public static CompletableFuture<WarnAction> warn(Sx4 bot, Member target, Member moderator, Reason reason) {
CompletableFuture<WarnAction> future = new CompletableFuture<>();
Guild guild = target.getGuild();
Document data = bot.getMongo().getGuildById(guild.getIdLong(), Projections.include("warn", "mute", "temporaryBan", "fakePermissions"));
List<Document> fakePermissions = data.getEmbedded(List.of("fakePermissions", "holders"), Collections.emptyList());
Document warnData = data.get("warn", MongoDatabase.EMPTY_DOCUMENT);
List<Document> config = warnData.getList("config", Document.class, Warn.DEFAULT_CONFIG);
boolean punishments = warnData.getBoolean("punishments", true);
Document reset = warnData.get("reset", Document.class);
int maxWarning = punishments ? config.stream().map(d -> d.getInteger("number")).max(Integer::compareTo).get() : Integer.MAX_VALUE;
List<Bson> update = List.of(Operators.set("warnings", Operators.let(new Document("warnings", Operators.ifNull("$warnings", 0)), Operators.mod(Operators.cond(Operators.exists("$reset"), Operators.max(1, Operators.add(1, Operators.subtract("$$warnings", Operators.multiply(Operators.toInt(Operators.floor(Operators.divide(Operators.subtract(Operators.nowEpochSecond(), "$lastWarning"), "$reset.after"))), "$reset.amount")))), Operators.add("$$warnings", 1)), maxWarning))), Operators.set("lastWarning", Operators.nowEpochSecond()), reset == null ? Operators.unset("reset") : Operators.set("reset", reset));
FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER).projection(Projections.include("warnings")).upsert(true);
Bson filter = Filters.and(Filters.eq("userId", target.getIdLong()), Filters.eq("guildId", guild.getIdLong()));
bot.getMongo().findAndUpdateWarnings(filter, update, options).whenComplete((result, exception) -> {
if (exception != null) {
future.completeExceptionally(exception);
return;
}
int warnings = result.getInteger("warnings");
Action warnAction = new Action(ModAction.WARN);
Action currentAction = warnAction, nextAction = warnAction;
if (punishments) {
for (Document configData : config) {
int number = configData.getInteger("number");
if (number == warnings) {
currentAction = Action.fromData(configData.get("action", Document.class));
} else if (number == warnings + 1) {
nextAction = Action.fromData(configData.get("action", Document.class));
}
}
}
Action action = currentAction;
Warn currentWarning = new Warn(action, warnings);
Warn nextWarning = new Warn(nextAction, warnings + 1);
switch(action.getModAction()) {
case WARN:
bot.getModActionManager().onModAction(new WarnEvent(moderator, target.getUser(), reason, currentWarning, nextWarning));
future.complete(new WarnAction(currentWarning));
break;
case MUTE_EXTEND:
case MUTE:
if (!guild.getSelfMember().hasPermission(Permission.MANAGE_ROLES)) {
future.completeExceptionally(new BotPermissionException(Permission.MANAGE_ROLES));
return;
}
AtomicReference<Role> atomicRole = new AtomicReference<>();
Document mute = data.get("mute", MongoDatabase.EMPTY_DOCUMENT);
long muteDuration = ((TimeAction) action).getDuration();
boolean extend = action.getModAction().isExtend();
ModUtility.upsertMuteRole(bot.getMongo(), guild, mute.get("roleId", 0L), mute.get("autoUpdate", true)).thenCompose(role -> {
atomicRole.set(role);
List<Bson> muteUpdate = List.of(Operators.set("unmuteAt", Operators.add(muteDuration, Operators.cond(Operators.and(extend, Operators.exists("$unmuteAt")), "$unmuteAt", Operators.nowEpochSecond()))));
Bson muteFilter = Filters.and(Filters.eq("userId", target.getIdLong()), Filters.eq("guildId", guild.getIdLong()));
return bot.getMongo().updateMute(muteFilter, muteUpdate, new UpdateOptions().upsert(true));
}).whenComplete((muteResult, muteException) -> {
if (muteException != null) {
future.completeExceptionally(muteException);
return;
}
Role role = atomicRole.get();
guild.addRoleToMember(target, role).reason(ModUtility.getAuditReason(reason, moderator.getUser())).queue($ -> {
bot.getMuteManager().putMute(guild.getIdLong(), target.getIdLong(), role.getIdLong(), muteDuration, extend && muteResult.getUpsertedId() == null);
bot.getModActionManager().onModAction(new WarnEvent(moderator, target.getUser(), reason, currentWarning, nextWarning));
future.complete(new WarnAction(currentWarning));
});
});
break;
case KICK:
if (!guild.getSelfMember().hasPermission(Permission.KICK_MEMBERS)) {
future.completeExceptionally(new BotPermissionException(Permission.KICK_MEMBERS));
return;
}
if (!guild.getSelfMember().canInteract(target)) {
future.completeExceptionally(new BotHierarchyException("kick"));
return;
}
if (!CheckUtility.hasPermissions(bot, moderator, fakePermissions, Permission.KICK_MEMBERS)) {
future.completeExceptionally(new AuthorPermissionException(Permission.KICK_MEMBERS));
return;
}
target.kick(ModUtility.getAuditReason(reason, moderator.getUser())).queue($ -> {
bot.getModActionManager().onModAction(new WarnEvent(moderator, target.getUser(), reason, currentWarning, nextWarning));
future.complete(new WarnAction(currentWarning));
});
break;
case TEMPORARY_BAN:
if (!guild.getSelfMember().hasPermission(Permission.BAN_MEMBERS)) {
future.completeExceptionally(new BotPermissionException(Permission.BAN_MEMBERS));
return;
}
if (!guild.getSelfMember().canInteract(target)) {
future.completeExceptionally(new BotHierarchyException("ban"));
return;
}
if (!CheckUtility.hasPermissions(bot, moderator, fakePermissions, Permission.BAN_MEMBERS)) {
future.completeExceptionally(new AuthorPermissionException(Permission.BAN_MEMBERS));
return;
}
long temporaryBanDuration = ((TimeAction) action).getDuration();
Bson temporaryBanUpdate = Updates.set("unbanAt", Clock.systemUTC().instant().getEpochSecond() + temporaryBanDuration);
Bson temporaryBanFilter = Filters.and(Filters.eq("userId", target.getIdLong()), Filters.eq("guildId", guild.getIdLong()));
bot.getMongo().updateTemporaryBan(temporaryBanFilter, temporaryBanUpdate, new UpdateOptions().upsert(true)).whenComplete((temporaryBanResult, temporaryBanException) -> {
if (temporaryBanException != null) {
future.completeExceptionally(temporaryBanException);
return;
}
target.ban(1).reason(ModUtility.getAuditReason(reason, moderator.getUser())).queue($ -> {
bot.getModActionManager().onModAction(new WarnEvent(moderator, target.getUser(), reason, currentWarning, nextWarning));
bot.getTemporaryBanManager().putBan(guild.getIdLong(), target.getIdLong(), ((TimeAction) action).getDuration());
future.complete(new WarnAction(currentWarning));
});
});
break;
case BAN:
if (!guild.getSelfMember().hasPermission(Permission.BAN_MEMBERS)) {
future.completeExceptionally(new BotPermissionException(Permission.BAN_MEMBERS));
return;
}
if (!guild.getSelfMember().canInteract(target)) {
future.completeExceptionally(new BotHierarchyException("ban"));
return;
}
if (!CheckUtility.hasPermissions(bot, moderator, fakePermissions, Permission.BAN_MEMBERS)) {
future.completeExceptionally(new AuthorPermissionException(Permission.BAN_MEMBERS));
return;
}
target.ban(1).reason(ModUtility.getAuditReason(reason, moderator.getUser())).queue($ -> {
bot.getModActionManager().onModAction(new WarnEvent(moderator, target.getUser(), reason, currentWarning, nextWarning));
future.complete(new WarnAction(currentWarning));
});
break;
default:
break;
}
});
return future;
}
use of com.sx4.bot.core.Sx4 in project Sx4 by sx4-discord-bot.
the class SuggestionManager method sendSuggestion.
public CompletableFuture<ReadonlyMessage> sendSuggestion(BaseGuildMessageChannel channel, Document webhookData, boolean premium, WebhookEmbed embed) {
User selfUser = channel.getJDA().getSelfUser();
WebhookMessage message = new WebhookMessageBuilder().setAvatarUrl(webhookData.get("avatar", selfUser.getEffectiveAvatarUrl())).setUsername(webhookData.get("name", "Sx4 - Suggestions")).addEmbeds(embed).build();
WebhookClient webhook;
if (this.webhooks.containsKey(channel.getIdLong())) {
webhook = this.webhooks.get(channel.getIdLong());
} else if (!webhookData.containsKey("id")) {
return this.createWebhook(channel, message);
} else {
webhook = new WebhookClient(webhookData.getLong("id"), webhookData.getString("token"), this.executor, this.client);
this.webhooks.put(channel.getIdLong(), webhook);
}
return webhook.send(message).thenApply(webhookMessage -> new ReadonlyMessage(webhookMessage, webhook.getId(), webhook.getToken())).exceptionallyCompose(exception -> {
Throwable cause = exception instanceof CompletionException ? exception.getCause() : exception;
if (cause instanceof HttpException && ((HttpException) cause).getCode() == 404) {
this.webhooks.remove(channel.getIdLong());
return this.createWebhook(channel, message);
}
return CompletableFuture.failedFuture(exception);
});
}
use of com.sx4.bot.core.Sx4 in project Sx4 by sx4-discord-bot.
the class FreeGameManager method sendFreeGameNotifications.
public CompletableFuture<List<ReadonlyMessage>> sendFreeGameNotifications(List<? extends FreeGame<?>> games) {
if (games.isEmpty()) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
games.forEach(this::addAnnouncedGame);
List<Document> gameData = games.stream().map(FreeGame::toData).collect(Collectors.toList());
this.bot.getMongo().insertManyAnnouncedGames(gameData).whenComplete(MongoDatabase.exceptionally());
List<Bson> guildPipeline = List.of(Aggregates.match(Operators.expr(Operators.eq("$_id", "$$guildId"))), Aggregates.project(Projections.computed("premium", Operators.lt(Operators.nowEpochSecond(), Operators.ifNull("$premium.endAt", 0L)))));
List<Bson> pipeline = List.of(Aggregates.lookup("guilds", List.of(new Variable<>("guildId", "$guildId")), guildPipeline, "premium"), Aggregates.addFields(new Field<>("premium", Operators.cond(Operators.isEmpty("$premium"), false, Operators.get(Operators.arrayElemAt("$premium", 0), "premium")))));
return this.bot.getMongo().aggregateFreeGameChannels(pipeline).thenComposeAsync(documents -> {
List<WriteModel<Document>> bulkData = new ArrayList<>();
List<CompletableFuture<List<ReadonlyMessage>>> futures = new ArrayList<>();
for (Document data : documents) {
if (!data.getBoolean("enabled", true)) {
continue;
}
BaseGuildMessageChannel channel = this.bot.getShardManager().getChannelById(BaseGuildMessageChannel.class, data.getLong("channelId"));
if (channel == null) {
continue;
}
String avatar = channel.getJDA().getSelfUser().getEffectiveAvatarUrl();
boolean premium = data.getBoolean("premium");
Document webhookData = data.get("webhook", MongoDatabase.EMPTY_DOCUMENT);
long platforms = data.get("platforms", FreeGameType.ALL);
List<WebhookMessage> messages = new ArrayList<>();
for (FreeGame<?> game : games) {
long raw = game.getType().getRaw();
if ((platforms & raw) != raw) {
continue;
}
Formatter<Document> formatter = new JsonFormatter(data.get("message", FreeGameManager.DEFAULT_MESSAGE)).addVariable("game", game);
WebhookMessage message;
try {
message = MessageUtility.fromJson(formatter.parse()).setAvatarUrl(premium ? webhookData.get("avatar", avatar) : avatar).setUsername(premium ? webhookData.get("name", "Sx4 - Free Games") : "Sx4 - Free Games").build();
} catch (IllegalArgumentException e) {
bulkData.add(new UpdateOneModel<>(Filters.eq("_id", data.getObjectId("_id")), Updates.unset("message")));
continue;
}
messages.add(message);
}
if (messages.isEmpty()) {
continue;
}
WebhookMessage firstMessage = messages.get(0);
String firstContent = firstMessage.getContent();
if (messages.size() == 1 || !messages.stream().skip(1).allMatch(message -> message.getContent().equals(firstContent))) {
futures.add(this.sendFreeGameNotificationMessages(channel, webhookData, messages));
continue;
}
List<WebhookMessage> updatedMessages = new ArrayList<>();
WebhookMessageBuilder baseMessage = new WebhookMessageBuilder().setContent(firstContent).setAvatarUrl(firstMessage.getAvatarUrl()).setUsername(firstMessage.getUsername());
int length = 0;
List<WebhookEmbed> embeds = new ArrayList<>();
for (WebhookMessage message : messages) {
List<WebhookEmbed> nextEmbeds = message.getEmbeds();
int nextLength = MessageUtility.getWebhookEmbedLength(nextEmbeds);
if (embeds.size() + nextEmbeds.size() > WebhookMessage.MAX_EMBEDS || length + nextLength > MessageEmbed.EMBED_MAX_LENGTH_BOT) {
baseMessage.addEmbeds(embeds);
updatedMessages.add(baseMessage.build());
baseMessage.resetEmbeds();
embeds.clear();
embeds.addAll(nextEmbeds);
length = nextLength;
continue;
}
embeds.addAll(nextEmbeds);
length += nextLength;
}
baseMessage.addEmbeds(embeds);
updatedMessages.add(baseMessage.build());
futures.add(this.sendFreeGameNotificationMessages(channel, webhookData, updatedMessages));
}
if (!bulkData.isEmpty()) {
this.bot.getMongo().bulkWriteFreeGameChannels(bulkData).whenComplete(MongoDatabase.exceptionally());
}
return FutureUtility.allOf(futures).thenApply(list -> list.stream().flatMap(List::stream).collect(Collectors.toList()));
});
}
Aggregations