package net.frozenorb.apiv3.model; import com.mongodb.async.SingleResultCallback; import com.mongodb.async.client.MongoCollection; import com.mongodb.client.result.UpdateResult; import fr.javatic.mongo.jacksonCodec.Entity; import fr.javatic.mongo.jacksonCodec.objectId.Id; import lombok.AllArgsConstructor; import lombok.Getter; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.SyncUtils; import net.frozenorb.apiv3.util.TimeUtils; import org.bson.Document; import org.bson.types.ObjectId; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @Entity @AllArgsConstructor public final class Punishment { private static final MongoCollection punishmentsCollection = APIv3.getDatabase().getCollection("punishments", Punishment.class); @Getter @Id private String id; @Getter private UUID user; @Getter private String reason; @Getter private PunishmentType type; @Getter private Instant expiresAt; @Getter private Map metadata; @Getter private String linkedIpBanId; @Getter private UUID addedBy; @Getter private Instant addedAt; @Getter private String actorName; @Getter private ActorType actorType; @Getter private UUID removedBy; @Getter private Instant removedAt; @Getter private String removalReason; public static List findByTypeSync(Collection types) { Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); return SyncUtils.blockMulti(punishmentsCollection.find(new Document("type", new Document("$in", convertedTypes)))); } public static Punishment findByIdSync(String id) { return SyncUtils.blockOne(punishmentsCollection.find(new Document("_id", id))); } public static List findByUserSync(User user) { return findByUserSync(user.getId()); } public static List findByUserSync(UUID user) { return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user))); } public static List findByUserAndTypeSync(User user, Collection types) { return findByUserAndTypeSync(user.getId(), types); } public static List findByUserAndTypeSync(UUID user, Collection types) { Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); return SyncUtils.blockMulti(punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes)))); } public static void findAllPaginated(int skip, int pageSize, SingleResultCallback> callback) { punishmentsCollection.find().sort(new Document("addedAt", -1)).skip(skip).limit(pageSize).into(new ArrayList<>(), callback); } public static void findById(String id, SingleResultCallback callback) { punishmentsCollection.find(new Document("_id", id)).first(callback); } public static void findByLinkedIpBanId(String id, SingleResultCallback callback) { punishmentsCollection.find(new Document("linkedIpBanId", id)).first(callback); } public static void findByUser(User user, SingleResultCallback> callback) { findByUser(user.getId(), callback); } public static void findByUser(UUID user, SingleResultCallback> callback) { punishmentsCollection.find(new Document("user", user)).into(new ArrayList<>(), callback); } public static void findByUserGrouped(Iterable users, SingleResultCallback>> callback) { punishmentsCollection.find(new Document("user", new Document("$in", users))).into(new ArrayList<>(), (punishments, error) -> { if (error != null) { callback.onResult(null, error); } else { Map> result = new HashMap<>(); for (UUID user : users) { result.put(user, new ArrayList<>()); } for (Punishment punishment : punishments) { result.get(punishment.getUser()).add(punishment); } callback.onResult(result, null); } }); } public static void findByUserAndType(User user, Collection types, SingleResultCallback> callback) { findByUserAndType(user.getId(), types, callback); } public static void findByUserAndType(UUID user, Collection types, SingleResultCallback> callback) { Collection convertedTypes = types.stream().map(PunishmentType::name).collect(Collectors.toList()); punishmentsCollection.find(new Document("user", user).append("type", new Document("$in", convertedTypes))).into(new ArrayList<>(), callback); } public Punishment() {} // For Jackson public Punishment(User user, String reason, PunishmentType type, Instant expiresAt, User addedBy, Actor actor, Map metadata) { this.id = new ObjectId().toString(); this.user = user.getId(); this.reason = reason; this.type = type; this.expiresAt = expiresAt; this.addedBy = addedBy == null ? null : addedBy.getId(); this.addedAt = Instant.now(); this.actorName = actor.getName(); this.actorType = actor.getType(); this.metadata = metadata; } public boolean isActive() { return !(isExpired() || isRemoved()); } public boolean isExpired() { return expiresAt != null && expiresAt.isBefore(Instant.now()); } public boolean isRemoved() { return removedBy != null; } public String getAccessDenialReason() { switch (type) { case BLACKLIST: return "Your account has been blacklisted from the MineHQ Network. \n\nThis type of punishment cannot be appealed."; case BAN: String accessDenialReason = "Your account has been suspended from the MineHQ Network. \n\n"; if (getExpiresAt() != null) { accessDenialReason += "Expires in " + TimeUtils.formatIntoDetailedString(TimeUtils.getSecondsBetween(getExpiresAt(), Instant.now())); } else { accessDenialReason += "Appeal at MineHQ.com/appeal"; } return accessDenialReason; default: return null; } } public void linkIpBan(IpBan ipBan) { this.linkedIpBanId = ipBan.getId(); } public void insert() { BlockingCallback callback = new BlockingCallback<>(); punishmentsCollection.insertOne(this, callback); callback.get(); } public void delete(User removedBy, String reason) { this.removedBy = removedBy.getId(); this.removedAt = Instant.now(); this.removalReason = reason; if (linkedIpBanId != null) { IpBan ipBan = IpBan.findByIdSync(linkedIpBanId); if (ipBan != null && ipBan.isActive()) { ipBan.delete(removedBy, "Linked punishment removed: " + reason); } } BlockingCallback callback = new BlockingCallback<>(); punishmentsCollection.replaceOne(new Document("_id", id), this, callback); callback.get(); } public enum PunishmentType { BLACKLIST, BAN, MUTE, WARN } }