use of com.sx4.bot.entities.mod.action.Action in project Sx4 by sx4-discord-bot.
the class ShipCommand method onCommand.
public void onCommand(Sx4CommandEvent event, @Argument(value = "first user") Member firstMember, @Argument(value = "second user", endless = true, nullDefault = true) Member secondMember) {
User firstUser = firstMember.getUser();
User secondUser = secondMember == null ? event.getAuthor() : secondMember.getUser();
this.random.setSeed(firstUser.getIdLong() + secondUser.getIdLong());
int percent = this.random.nextInt(100) + 1;
String firstName = firstUser.getName(), secondName = secondUser.getName();
String shipName = firstName.substring(0, (int) Math.ceil((double) firstName.length() / 2)) + secondName.substring((int) Math.ceil((double) secondName.length() / 2));
String message = String.format("Ship Name: **%s**\nLove Percentage: **%d%%**", shipName, percent);
Request request = new ImageRequest(event.getConfig().getImageWebserverUrl("ship")).addQuery("first_image", firstUser.getEffectiveAvatarUrl()).addQuery("second_image", secondUser.getEffectiveAvatarUrl()).addQuery("percent", percent).build(event.getConfig().getImageWebserver());
if (event.getSelfMember().hasPermission(event.getTextChannel(), Permission.MESSAGE_ATTACH_FILES)) {
event.getHttpClient().newCall(request).enqueue((HttpCallback) response -> {
MessageAction action = ImageUtility.getImageMessage(event, response);
if (response.isSuccessful()) {
action.content(message);
}
action.queue();
});
} else {
event.reply(message).queue();
}
}
use of com.sx4.bot.entities.mod.action.Action in project Sx4 by sx4-discord-bot.
the class PremiumCommand method add.
@Command(value = "add", description = "Make a server premium")
@CommandId(177)
@Examples({ "premium add", "premium add 31", "premium add 20 Sx4 | Support Server" })
@Premium
public void add(Sx4CommandEvent event, @Argument(value = "days") @DefaultNumber(31) @Limit(min = 1, max = 365) int days, @Argument(value = "server", endless = true, nullDefault = true) Guild guild) {
if (guild == null) {
guild = event.getGuild();
}
long guildId = guild.getIdLong();
String guildName = guild.getName();
int monthPrice = event.getConfig().getPremiumPrice();
int price = (int) Math.round((monthPrice / (double) event.getConfig().getPremiumDays()) * days);
long endAtPrior = event.getMongo().getGuildById(guildId, Projections.include("premium.endAt")).getEmbedded(List.of("premium", "endAt"), 0L);
boolean hasPremium = endAtPrior != 0;
MessageEmbed embed = new EmbedBuilder().setColor(event.getConfig().getOrange()).setAuthor("Premium", null, event.getAuthor().getEffectiveAvatarUrl()).setDescription(String.format("Buying %d day%s of premium will:\n\n• Make you unable to use this credit on the other version of the bot\n• Use **$%.2f** of your credit\n• %s %1$s day%2$s of premium to the server\n\n:warning: **This action cannot be reversed** :warning:", days, days == 1 ? "" : "s", price / 100D, hasPremium ? "Add an extra" : "Give")).build();
List<Button> buttons = List.of(Button.success("confirm", "Confirm"), Button.danger("cancel", "Cancel"));
event.reply(embed).setActionRow(buttons).submit().thenCompose(message -> {
return new Waiter<>(event.getBot(), ButtonClickEvent.class).setPredicate(e -> ButtonUtility.handleButtonConfirmation(e, message, event.getAuthor(), "confirm")).setCancelPredicate(e -> ButtonUtility.handleButtonCancellation(e, message, event.getAuthor(), "cancel")).onFailure(e -> ButtonUtility.handleButtonFailure(e, message)).setTimeout(60).start();
}).whenComplete((e, exception) -> {
Throwable cause = exception instanceof CompletionException ? exception.getCause() : exception;
if (cause instanceof CancelException) {
GenericEvent cancelEvent = ((CancelException) cause).getEvent();
if (cancelEvent != null) {
((ButtonClickEvent) cancelEvent).reply("Cancelled " + event.getConfig().getSuccessEmote()).queue();
}
return;
} else if (cause instanceof TimeoutException) {
event.reply("Timed out :stopwatch:").queue();
return;
} else if (ExceptionUtility.sendExceptionally(event, exception)) {
return;
}
List<Bson> update = List.of(Operators.set("premium.credit", Operators.cond(Operators.gt(price, Operators.ifNull("$premium.credit", 0)), "$premium.credit", Operators.subtract("$premium.credit", price))));
FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.BEFORE).projection(Projections.include("premium.credit")).upsert(true);
event.getMongoMain().findAndUpdateUserById(event.getAuthor().getIdLong(), update, options).thenCompose(data -> {
int credit = data == null ? 0 : data.getEmbedded(List.of("premium", "credit"), 0);
if (price > credit) {
e.reply("You do not have enough credit to buy premium for that long " + event.getConfig().getFailureEmote()).queue();
return CompletableFuture.completedFuture(MongoDatabase.EMPTY_DOCUMENT);
}
List<Bson> guildUpdate = List.of(Operators.set("premium.endAt", Operators.add(TimeUnit.DAYS.toSeconds(days), Operators.ifNull("$premium.endAt", Operators.nowEpochSecond()))));
FindOneAndUpdateOptions guildOptions = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.BEFORE).projection(Projections.include("premium.endAt")).upsert(true);
return event.getMongo().findAndUpdateGuildById(guildId, guildUpdate, guildOptions);
}).whenComplete((data, databaseException) -> {
if (ExceptionUtility.sendExceptionally(event, databaseException) || (data != null && data.isEmpty())) {
return;
}
long endAt = data == null ? 0L : data.getEmbedded(List.of("premium", "endAt"), 0L);
e.replyFormat("**%s** now has premium for %s%d day%s %s", guildName, endAt == 0 ? "" : "another ", days, days == 1 ? "" : "s", event.getConfig().getSuccessEmote()).queue();
});
});
}
use of com.sx4.bot.entities.mod.action.Action in project Sx4 by sx4-discord-bot.
the class AntiRegexHandler method handle.
public void handle(Message message) {
Member member = message.getMember();
if (member == null) {
return;
}
User user = member.getUser();
if (user.isBot()) {
return;
}
Guild guild = message.getGuild();
Member selfMember = guild.getSelfMember();
TextChannel textChannel = message.getTextChannel();
long guildId = guild.getIdLong(), userId = member.getIdLong(), channelId = textChannel.getIdLong();
Category parent = textChannel.getParent();
List<Role> roles = member.getRoles();
String content = message.getContentRaw();
List<Bson> guildPipeline = List.of(Aggregates.project(Projections.fields(Projections.computed("premium", Operators.lt(Operators.nowEpochSecond(), Operators.ifNull("$premium.endAt", 0L))), Projections.computed("guildId", "$_id"))), Aggregates.match(Filters.eq("guildId", guild.getIdLong())));
List<Bson> pipeline = List.of(Aggregates.match(Filters.and(Filters.eq("guildId", guild.getIdLong()), Filters.exists("enabled", false))), Aggregates.group(null, Accumulators.push("regexes", Operators.ROOT)), Aggregates.unionWith("guilds", guildPipeline), Aggregates.group(null, Accumulators.max("premium", "$premium"), Accumulators.max("regexes", "$regexes")), Aggregates.project(Projections.computed("regexes", Operators.let(new Document("regexes", Operators.ifNull("$regexes", Collections.EMPTY_LIST)), Operators.cond(Operators.ifNull("$premium", false), "$$regexes", Operators.concatArrays(Operators.filter("$$regexes", Operators.ne("$$this.type", RegexType.REGEX.getId())), Operators.slice(Operators.filter("$$regexes", Operators.eq("$$this.type", RegexType.REGEX.getId())), 0, 3)))))));
this.bot.getMongo().aggregateRegexes(pipeline).whenComplete((documents, exception) -> {
if (documents.isEmpty()) {
return;
}
Document data = documents.get(0);
this.executor.submit(() -> {
List<CompletableFuture<Document>> matches = new ArrayList<>();
Regexes: for (Document regex : data.getList("regexes", Document.class)) {
if (member.hasPermission(Permission.ADMINISTRATOR) && regex.getBoolean("admin", true)) {
continue;
}
List<Document> channels = regex.getList("whitelist", Document.class, Collections.emptyList());
Document channel = channels.stream().filter(d -> (d.getInteger("type") == WhitelistType.CHANNEL.getId() && d.getLong("id") == channelId) || (d.getInteger("type") == WhitelistType.CATEGORY.getId() && parent != null && d.getLong("id") == parent.getIdLong())).min(Comparator.comparingInt(d -> d.getInteger("type", 0))).orElse(MongoDatabase.EMPTY_DOCUMENT);
List<Document> holders = channel.getList("holders", Document.class, Collections.emptyList());
for (Document holder : holders) {
long holderId = holder.getLong("id");
int type = holder.getInteger("type");
if (type == HolderType.USER.getType() && userId == holderId) {
continue Regexes;
} else if (type == HolderType.ROLE.getType() && (guildId == holderId || roles.stream().anyMatch(role -> role.getIdLong() == holderId))) {
continue Regexes;
}
}
RegexType type = RegexType.fromId(regex.getInteger("type"));
Pattern pattern = type == RegexType.REGEX ? Pattern.compile(regex.getString("pattern")) : this.invitePattern;
Matcher matcher;
try {
matcher = this.executor.submit(() -> pattern.matcher(content)).get(2000, TimeUnit.MILLISECONDS);
} catch (TimeoutException | InterruptedException | ExecutionException e) {
continue;
}
Set<String> codes = new HashSet<>();
int matchCount = 0, totalCount = 0;
while (matcher.find()) {
List<Document> groups = channel.getList("groups", Document.class, Collections.emptyList());
for (Document group : groups) {
List<String> strings = group.getList("strings", String.class, Collections.emptyList());
String match = matcher.group(group.getInteger("group"));
if (match != null && strings.contains(match)) {
matchCount++;
}
}
if (type == RegexType.INVITE) {
codes.add(matcher.group(1));
}
totalCount++;
}
if (matchCount == totalCount) {
continue;
}
CompletableFuture<Document> future;
if (type == RegexType.INVITE) {
List<CompletableFuture<Invite>> futures = codes.stream().map(code -> Invite.resolve(message.getJDA(), code, true).submit()).collect(Collectors.toList());
List<Long> guilds = channel.getList("guilds", Long.class, Collections.emptyList());
future = FutureUtility.anyOf(futures, invite -> {
Invite.Guild inviteGuild = invite.getGuild();
return inviteGuild == null || (!guilds.contains(inviteGuild.getIdLong()) && inviteGuild.getIdLong() != guildId);
}).thenApply(invite -> invite == null ? null : regex);
} else {
future = CompletableFuture.completedFuture(regex);
}
matches.add(future);
}
FutureUtility.anyOf(matches, Objects::nonNull).thenAccept(regex -> {
if (regex == null) {
return;
}
ObjectId id = regex.getObjectId("_id");
RegexType type = RegexType.fromId(regex.getInteger("type"));
Document match = regex.get("match", MongoDatabase.EMPTY_DOCUMENT);
long matchAction = match.get("action", MatchAction.ALL);
Document mod = regex.get("mod", MongoDatabase.EMPTY_DOCUMENT);
Document actionData = mod.get("action", Document.class);
Action action = actionData == null ? null : Action.fromData(actionData);
Document attempts = regex.get("attempts", MongoDatabase.EMPTY_DOCUMENT);
int maxAttempts = attempts.get("amount", 3);
if ((matchAction & MatchAction.DELETE_MESSAGE.getRaw()) == MatchAction.DELETE_MESSAGE.getRaw() && selfMember.hasPermission(textChannel, Permission.MESSAGE_MANAGE)) {
message.delete().queue();
}
Document reset = attempts.get("reset", Document.class);
List<Bson> update = List.of(Operators.set("attempts", Operators.let(new Document("attempts", Operators.ifNull("$attempts", 0)), Operators.cond(Operators.exists("$reset"), Operators.max(1, Operators.add(1, Operators.subtract("$$attempts", Operators.multiply(Operators.toInt(Operators.floor(Operators.divide(Operators.subtract(Operators.nowEpochSecond(), "$lastAttempt"), "$reset.after"))), "$reset.amount")))), Operators.add("$$attempts", 1)))), Operators.set("lastAttempt", Operators.nowEpochSecond()), Operators.setOnInsert("guildId", guildId), reset == null ? Operators.unset("reset") : Operators.set("reset", reset));
Bson filter = Filters.and(Filters.eq("userId", userId), Filters.eq("regexId", id));
FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().upsert(true).projection(Projections.include("attempts")).returnDocument(ReturnDocument.AFTER);
this.bot.getMongo().findAndUpdateRegexAttempt(filter, update, options).whenComplete((attemptsData, attemptsException) -> {
if (ExceptionUtility.sendErrorMessage(attemptsException)) {
return;
}
int currentAttempts = attemptsData.getInteger("attempts", 0);
String matchMessage = this.format(match.get("message", type.getDefaultMatchMessage()), user, textChannel, id, currentAttempts, maxAttempts, action);
String modMessage = this.format(mod.get("message", type.getDefaultModMessage()), user, textChannel, id, currentAttempts, maxAttempts, action);
boolean send = (matchAction & MatchAction.SEND_MESSAGE.getRaw()) == MatchAction.SEND_MESSAGE.getRaw() && selfMember.hasPermission(textChannel, Permission.MESSAGE_WRITE);
if (action != null && currentAttempts == maxAttempts) {
Reason reason = new Reason(String.format("Sent a message which matched regex `%s` %d time%s", id.toHexString(), maxAttempts, maxAttempts == 1 ? "" : "s"));
ModUtility.performAction(this.bot, action, member, selfMember, reason).thenCompose(result -> {
if (send) {
textChannel.sendMessage(modMessage).allowedMentions(EnumSet.allOf(Message.MentionType.class)).queue();
}
return this.bot.getMongo().deleteRegexAttempt(Filters.and(Filters.eq("userId", userId), Filters.eq("regexId", id)));
}).whenComplete((result, modException) -> {
Throwable cause = modException instanceof CompletionException ? modException.getCause() : modException;
if (cause instanceof ModException) {
textChannel.sendMessage(modException.getMessage() + " " + this.bot.getConfig().getFailureEmote()).queue();
return;
}
ExceptionUtility.sendExceptionally(textChannel, modException);
});
return;
}
if (send) {
textChannel.sendMessage(matchMessage).allowedMentions(EnumSet.allOf(Message.MentionType.class)).queue();
}
});
});
});
});
}
use of com.sx4.bot.entities.mod.action.Action in project Sx4 by sx4-discord-bot.
the class AntiInviteCommand method attempts.
/*@Command(value="set", description="Sets the amount of attempts a user has")
@CommandId(459)
@Examples({"antiinvite set @Shea#6653 0", "antiinvite set Shea 3", "antiinvite set 402557516728369153 2"})
@AuthorPermissions(permissions={Permission.MANAGE_SERVER})
public void set(Sx4CommandEvent event, @Argument(value="user") Member member, @Argument(value="attempts") int attempts) {
Bson filter = Filters.and(Filters.eq("regexId", AntiInviteCommand.REGEX_ID), Filters.eq("userId", member.getIdLong()), Filters.eq("guildId", event.getGuild().getIdLong()));
CompletableFuture<Document> future;
if (attempts == 0) {
future = event.getMongo().findAndDeleteRegexAttempt(filter);
} else {
FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().projection(Projections.include("attempts")).returnDocument(ReturnDocument.BEFORE).upsert(true);
future = event.getMongo().findAndUpdateRegexAttempt(filter, Updates.set("attempts", attempts), options);
}
future.whenComplete((data, exception) -> {
if (ExceptionUtility.sendExceptionally(event, exception)) {
return;
}
if (data == null) {
event.replyFailure("You do not have anti-invite setup").queue();
return;
}
if (data.getInteger("attempts") == attempts) {
event.replyFailure("That users attempts were already set to that").queue();
return;
}
if (attempts == 0) {
event.getBot().getAntiRegexManager().clearAttempts(AntiInviteCommand.REGEX_ID, member.getIdLong());
} else {
event.getBot().getAntiRegexManager().setAttempts(AntiInviteCommand.REGEX_ID, member.getIdLong(), attempts);
}
event.replySuccess("**" + member.getUser().getAsTag() + "** has had their attempts set to **" + attempts + "**").queue();
});
}*/
@Command(value = "attempts", description = "Sets the amount of attempts needed for the mod action to execute")
@CommandId(307)
@Examples({ "antiinvite attempts 3", "antiinvite attempts 1" })
@AuthorPermissions(permissions = { Permission.MANAGE_SERVER })
public void attempts(Sx4CommandEvent event, @Argument(value = "attempts") @Limit(min = 1) int attempts) {
Bson filter = Filters.and(Filters.eq("regexId", AntiInviteCommand.REGEX_ID), Filters.eq("guildId", event.getGuild().getIdLong()));
event.getMongo().updateRegex(filter, Updates.set("attempts.amount", attempts)).whenComplete((result, exception) -> {
if (ExceptionUtility.sendExceptionally(event, exception)) {
return;
}
if (result.getMatchedCount() == 0) {
event.replyFailure("You do not have anti-invite setup").queue();
return;
}
if (result.getModifiedCount() == 0) {
event.replyFailure("Your attempts where already set to that").queue();
return;
}
event.replySuccess("Attempts to a mod action have been set to **" + attempts + "**").queue();
});
}
use of com.sx4.bot.entities.mod.action.Action in project Sx4 by sx4-discord-bot.
the class AntiRegexCommand method formatters.
@Command(value = "formatters", aliases = { "format", "formatting" }, description = "Get all the formatters for anti regex you can use")
@CommandId(468)
@Examples({ "anti regex formatters" })
@BotPermissions(permissions = { Permission.MESSAGE_EMBED_LINKS })
public void formatters(Sx4CommandEvent event) {
EmbedBuilder embed = new EmbedBuilder().setAuthor("Anti-Regex Formatters", null, event.getSelfUser().getEffectiveAvatarUrl());
FormatterManager manager = FormatterManager.getDefaultManager();
StringJoiner content = new StringJoiner("\n");
for (FormatterVariable<?> variable : manager.getVariables(User.class)) {
content.add("`{user." + variable.getName() + "}` - " + variable.getDescription());
}
for (FormatterVariable<?> variable : manager.getVariables(TextChannel.class)) {
content.add("`{channel." + variable.getName() + "}` - " + variable.getDescription());
}
content.add("`{regex.id}` - Gets the id of the regex");
content.add("`{regex.action.name}` - Gets the mod action name if one is set");
content.add("`{regex.action.exists}` - Returns true or false if an action exists");
content.add("`{regex.attempts.current}` - Gets the current attempts for the user");
content.add("`{regex.attempts.max}` - Gets the max attempts set for the anti regex");
embed.setDescription(content.toString());
event.reply(embed.build()).queue();
}
Aggregations