public void onTimeoutExpire(User user, Server server) { String serverId = server.getId(); TempServerConfig serverConfig = serverStorage.get(serverId); if (serverConfig == null) { serverConfig = new TempServerConfig(serverId); serverStorage.put(serverId, serverConfig); } ServerTimeoutStorage storage = serverConfig.getServerTimeouts(); if (storage != null) { ServerTimeout timeout = storage.getTimeouts().remove(user.getId()); if (timeout != null) { saveServerConfig(serverConfig); LOGGER.info( "Expiring timeout for {} ({}) in {} ({})", user.getUsername(), user.getId(), server.getName(), server.getId()); if (apiClient.getUserById(user.getId(), server) != NO_USER) { apiClient.sendMessage( loc.localize("message.mod.timeout.expire", user.getId()), server.getId()); } removeTimeoutRole(user, server, apiClient.getChannelById(server.getId())); return; } } LOGGER.warn( "Unable to expire: find server or timeout entry for {} ({}) in {} ({})", user.getUsername(), user.getId(), server.getName(), server.getId()); }
private void refreshTimeoutOnEvade(User user, Server server) { ServerTimeout timeout = SafeNav.of(serverStorage.get(server.getId())) .next(TempServerConfig::getServerTimeouts) .next(ServerTimeoutStorage::getTimeouts) .next(timeouts -> timeouts.get(user.getId())) .get(); if (timeout == null) { LOGGER.warn( "Attempted to refresh a timeout on a user who was not timed out! {} ({})", user.getUsername(), user.getId()); return; } LOGGER.info( "User {} ({}) attempted to evade a timeout on {} ({})!", user.getUsername(), user.getId(), server.getName(), server.getId()); Channel channel = apiClient.getChannelById(server.getId(), server); apiClient.sendMessage( loc.localize( "listener.mod.timeout.on_evasion", user.getId(), formatDuration(Duration.between(Instant.now(), timeout.getEndTime())), formatInstant(timeout.getEndTime())), channel); applyTimeoutRole(user, server, channel); }
private void stopTimeout(MessageContext context, String args) { if (args.isEmpty()) { apiClient.sendMessage( loc.localize("commands.mod.stoptimeout.response.invalid"), context.getChannel()); return; } String uid = args; if (uid.length() > 4) { if (uid.startsWith("<@")) { uid = uid.substring(2, uid.length() - 1); } Server server = context.getServer(); User user = apiClient.getUserById(uid, server); if (user == NO_USER) { user = new User("UNKNOWN", uid, "", null); } LOGGER.info( "{} ({}) is attempting to cancel timeout for {} ({}) in {} ({})", context.getAuthor().getUsername(), context.getAuthor().getId(), user.getUsername(), user.getId(), server.getName(), server.getId()); cancelTimeout(user, server, context.getChannel()); } else { apiClient.sendMessage( loc.localize("commands.mod.stoptimeout.response.invalid"), context.getChannel()); } }
private String userToResult(User user) { return loc.localize( "commands.admin.find.response.entry", user.getUsername(), user.getId(), user.getDiscriminator()); }
private void ban(MessageContext context, String args) { if (args.isEmpty()) { return; } String[] split = args.split(" "); List<String> banned = new ArrayList<>(); List<String> failed = new ArrayList<>(); Channel channel = context.getChannel(); for (String userStr : split) { User user = findUser(context, userStr); String userId = user.getId(); if (user == NO_USER) { userId = userStr; } if (banChecked(channel, context.getAuthor(), user, context.getServer())) { banned.add(userId + " " + user.getUsername()); } else { failed.add(userId + " " + user.getUsername()); } } if (channel.getId() != null) { StringJoiner joiner = new StringJoiner("\n"); for (String s : banned) { String[] pair = s.split(" ", 2); joiner.add(loc.localize("commands.mod.ban.response", pair[1], pair[0])); } apiClient.sendMessage(joiner.toString(), channel); } }
public boolean banChecked(Channel channel, User author, User user, Server server) { String userId = user.getId(); if (userId.equals(author.getId())) { apiClient.sendMessage("You cannot ban yourself", channel); return false; } if (userId.equals(apiClient.getClientUser().getId())) { apiClient.sendMessage("You cannot ban the bot", channel); return false; } if (bot.getCommands() .checkPermission( Permission.GEN_MANAGE_ROLES, apiClient.getUserMember(userId, server), server, apiClient)) { apiClient.sendMessage("You cannot ban an admin", channel); return false; } return banImpl(userId, server.getId()); }
public void cancelTimeout(User user, Server server, Channel invocationChannel) { String serverId = server.getId(); TempServerConfig serverConfig = serverStorage.get(serverId); if (serverConfig == null) { serverConfig = new TempServerConfig(serverId); serverStorage.put(serverId, serverConfig); } ServerTimeoutStorage storage = serverConfig.getServerTimeouts(); removeTimeoutRole(user, server, apiClient.getChannelById(serverId)); if (storage != null) { ServerTimeout timeout = storage.getTimeouts().remove(user.getId()); saveServerConfig(serverConfig); if (timeout != null) { SafeNav.of(timeout.getTimerFuture()).ifPresent(f -> f.cancel(true)); LOGGER.info( "Cancelling timeout for {} ({}) in {} ({})", user.getUsername(), user.getId(), server.getName(), serverId); apiClient.sendMessage( loc.localize("commands.mod.stoptimeout.response", user.getUsername(), user.getId()), invocationChannel); return; } } LOGGER.warn( "Unable to cancel: cannot find server or timeout entry for {} ({}) in {} ({})", user.getUsername(), user.getId(), server.getName(), server.getId()); apiClient.sendMessage( loc.localize( "commands.mod.stoptimeout.response.not_found", user.getUsername(), user.getId()), invocationChannel); }
public boolean applyTimeout( User issuingUser, Channel noticeChannel, Server server, User user, Duration duration) { String serverId = server.getId(); if (duration != null && !duration.isNegative() && !duration.isZero()) { ServerTimeout timeout = new ServerTimeout( duration, Instant.now(), user.getId(), serverId, user.getUsername(), issuingUser.getId()); TempServerConfig serverConfig = serverStorage.get(serverId); if (serverConfig == null) { serverConfig = new TempServerConfig(serverId); serverStorage.put(serverId, serverConfig); } ServerTimeoutStorage storage = serverConfig.getServerTimeouts(); if (storage == null) { storage = new ServerTimeoutStorage(); serverConfig.setServerTimeouts(storage); } if (applyTimeoutRole(user, server, noticeChannel)) { storage.getTimeouts().put(user.getId(), timeout); ScheduledFuture future = timeoutService.schedule( () -> onTimeoutExpire(user, server), duration.getSeconds(), TimeUnit.SECONDS); timeout.setTimerFuture(future); saveServerConfig(serverConfig); String durationStr = formatDuration(duration); String instantStr = formatInstant(timeout.getEndTime()); String msg = loc.localize( "commands.mod.timeout.response", user.getUsername(), user.getId(), durationStr, instantStr); apiClient.sendMessage(msg, noticeChannel); LOGGER.info( "[{}] '{}': Timing out {} ({}) for {} (until {}), issued by {} ({})", serverId, server.getName(), user.getUsername(), user.getId(), durationStr, instantStr, issuingUser.getUsername(), issuingUser.getId()); } // No else with error - applyTimeoutRole does that for us return true; } else { LOGGER.warn("Invalid duration format"); } return false; }
public boolean doesTimeoutEntryExistForUser(User user, Server server) { return doesTimeoutEntryExistForUser(user.getId(), server.getId()); }
public boolean isUserTimedOut(User user, Server server) { return isUserTimedOut(user.getId(), server.getId()); }
private void timeout(MessageContext context, String args) { Channel channel = context.getChannel(); if (!args.isEmpty()) { String[] split = args.split(" ", 2); String uid = split[0]; if (uid.length() > 4) { if (uid.startsWith("<@!")) { uid = uid.substring(3, uid.length() - 1); } else if (uid.startsWith("<@")) { uid = uid.substring(2, uid.length() - 1); } if (!uid.matches("[0-9]+")) { apiClient.sendMessage(loc.localize("commands.mod.stoptimeout.response.not_id"), channel); return; } Server server = context.getServer(); String serverId = server.getId(); User user = apiClient.getUserById(uid, server); if (user == NO_USER) { user = new User("UNKNOWN", uid, "", null); } final User theUser = user; if (split.length == 2) { if (bot.getConfig().isAdmin(user.getId())) { apiClient.sendMessage( "```API error: Server returned HTTP: 403 Forbidden. Check bot " + "permissions```", channel); return; } Duration duration = parseDuration(split[1]); if (applyTimeout(context.getAuthor(), channel, server, user, duration)) { return; } } else if (split.length == 1) { if (isUserTimedOut(user, server)) { ServerTimeout timeout = SafeNav.of(serverStorage.get(serverId)) .next(TempServerConfig::getServerTimeouts) .next(ServerTimeoutStorage::getTimeouts) .next(m -> m.get(theUser.getId())) .get(); // Timeout cannot be null since we just checked User timeoutIssuer = apiClient.getUserById(timeout.getIssuedByUserId(), server); apiClient.sendMessage( loc.localize( "commands.mod.timeout.response.check", user.getUsername(), user.getId(), formatDuration(Duration.between(Instant.now(), timeout.getEndTime())), formatInstant(timeout.getEndTime()), timeoutIssuer.getUsername(), timeout.getIssuedByUserId()), channel); } else { apiClient.sendMessage( loc.localize( "commands.mod.timeout.response.check.not_found", user.getUsername(), user.getId()), channel); } return; } else { LOGGER.warn("Split length not 1 or 2, was {}: '{}'", split.length, args); } } else { LOGGER.warn("UID/mention not long enough: '{}'", args); } } else { LOGGER.warn("Args was empty"); } apiClient.sendMessage(loc.localize("commands.mod.timeout.response.invalid"), channel); }
private void vanish(MessageContext context, String args) { Message message = context.getMessage(); if (args.isEmpty()) { return; } try { final int cap = 100; final int capPages = 10; String[] vals = args.split(" "); String userId; int numMsgs; if (vals.length == 2) { User user = findUser(context, vals[0]); userId = user.getId(); if (user == NO_USER) { userId = vals[0]; } numMsgs = Math.max(1, Math.min(cap, Integer.parseInt(vals[1]))); } else if (vals.length == 1) { userId = ""; numMsgs = Math.max(1, Math.min(cap, Integer.parseInt(vals[0]))); } else { userId = ""; numMsgs = 10; } int limit = numMsgs; String before = message.getId(); // Limit search to 10 pages (500 msgs) // Instead of deleting them when we find them, we build a list instead List<String> messagesToDelete = new ArrayList<>(limit); for (int k = 0; k < capPages && limit > 0; k++) { Map<String, String> headers = new HashMap<>(); headers.put(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); headers.put(HttpHeaders.AUTHORIZATION, apiClient.getToken()); Map<String, Object> queryParams = new HashMap<>(); queryParams.put("limit", 50); queryParams.put("before", before); HttpResponse<JsonNode> response = Unirest.get(ApiConst.CHANNELS_ENDPOINT + message.getChannelId() + "/messages") .headers(headers) .queryString(queryParams) .asJson(); JSONArray ret = response.getBody().getArray(); if (userId.isEmpty()) { for (int i = 0; i < ret.length() && limit > 0; i++) { JSONObject msg = ret.getJSONObject(i); String mid = msg.getString("id"); before = mid; messagesToDelete.add(mid); limit--; } } else { for (int i = 0; i < ret.length() && limit > 0; i++) { JSONObject msg = ret.getJSONObject(i); String mid = msg.getString("id"); JSONObject msgUsr = msg.getJSONObject("author"); String uid = msgUsr.getString("id"); before = mid; if (userId.equals(uid)) { messagesToDelete.add(mid); limit--; } } } } LOGGER.info("Deleting {} messages", messagesToDelete.size()); // Using bulk delete endpoint apiClient.bulkDeleteMessages( context.getChannel().getId(), messagesToDelete.toArray(new String[messagesToDelete.size()])); } catch (Exception e) { LOGGER.warn("Unable to get messages", e); } }
private void setNick(MessageContext context, String args) { if (context.getServer() == null || context.getServer() == NO_SERVER) { return; } String serverId = context.getServer().getId(); Channel channel = context.getChannel(); String[] split = args.split(" ", 2); String newNickname; if (split.length == 1) { // Clearing nickname, set to empty string newNickname = ""; } else { newNickname = split[1]; } User[] mentions = context.getMessage().getMentions(); if (mentions.length == 0) { apiClient.sendMessage(loc.localize("commands.mod.setnick.response.blank"), channel); } User target = mentions[0]; Map<String, String> headers = new HashMap<>(); headers.put(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); headers.put(HttpHeaders.AUTHORIZATION, apiClient.getToken()); try { HttpResponse<JsonNode> response = Unirest.patch( "https://discordapp.com/api/guilds/" + serverId + "/members/" + target.getId()) .headers(headers) .body("{\"nick\":\"" + newNickname + "\"}") .asJson(); int status = response.getStatus(); if (status != 204) { if (status == 403) { apiClient.sendMessage( loc.localize("commands.mod.setnick.response.failed.no_perms"), channel); } else if (status == 404) { apiClient.sendMessage( loc.localize("commands.mod.setnick.response.failed.not_found"), channel); } else { apiClient.sendMessage( loc.localize( "commands.mod.setnick.response.unknown_error", status, response.getStatusText(), response.getBody().toString()), channel); } } else { if (newNickname.isEmpty()) { apiClient.sendMessage( loc.localize("commands.mod.setnick.response.removed", target.getUsername()), channel); } else { apiClient.sendMessage( loc.localize( "commands.mod.setnick.response.changed", target.getUsername(), newNickname), channel); } } } catch (UnirestException e) { LOGGER.warn( "Exception while setting nickname for {} {} in {} {}", target.getUsername(), target.getId(), context.getServer().getName(), serverId); LOGGER.warn("Nickname set exception", e); } }
public void loadServerConfig(Path path) { boolean purge = false; TempServerConfig config; ServerTimeoutStorage storage; try (Reader reader = Files.newBufferedReader(path, UTF_8)) { config = gson.fromJson(reader, TempServerConfig.class); serverStorage.put(config.getServerId(), config); storage = config.getServerTimeouts(); if (storage != null) { Server server = apiClient.getServerByID(config.getServerId()); if (server == NO_SERVER) { LOGGER.warn("Rejecting {} server storage file: server not found", config.getServerId()); return; } LOGGER.info( "Loaded {} ({}) server storage file", server.getName(), server.getId(), storage.getTimeoutRoleId()); // Prune expired entries for (Iterator<Map.Entry<String, ServerTimeout>> iter = storage.getTimeouts().entrySet().iterator(); iter.hasNext(); ) { Map.Entry<String, ServerTimeout> e = iter.next(); ServerTimeout timeout = e.getValue(); String userId = timeout.getUserId(); User user = apiClient.getUserById(userId, server); if (!isUserTimedOut(userId, server.getId())) { // Purge! purge = true; if (user == NO_USER) { LOGGER.info( "Ending timeout for departed user {} ({}) in {} ({})", timeout.getLastUsername(), userId, server.getName(), server.getId()); // // apiClient.sendMessage(loc.localize("message.mod.timeout.expire.not_found", // user.getId()), // server.getId()); // Don't need to remove the timeout role because leaving does that for us } else { // Duplicated from onTimeoutExpire except without remove since we're removing in an // iter LOGGER.info( "Expiring timeout for {} ({}) in {} ({})", user.getUsername(), user.getId(), server.getName(), server.getId()); // Only send message if they still have the role if (removeTimeoutRole(user, server, apiClient.getChannelById(server.getId()))) { // // apiClient.sendMessage(loc.localize("message.mod.timeout.expire", // user.getId()), // server.getId()); } } SafeNav.of(timeout.getTimerFuture()).ifPresent(f -> f.cancel(true)); iter.remove(); } else { // Start our futures Duration duration = Duration.between(Instant.now(), timeout.getEndTime()); ScheduledFuture future = timeoutService.schedule( () -> onTimeoutExpire(user, server), duration.getSeconds(), TimeUnit.SECONDS); timeout.setTimerFuture(future); } } } } catch (IOException | JsonParseException e) { LOGGER.warn("Unable to load server storage file " + path.toString(), e); return; } if (purge) { saveServerConfig(config); } }