/* * Copyright 2019 Laurent PAGE, Apache Licence 2.0 */ package live.page.hubd.content.notices; import com.mongodb.client.model.*; import live.page.hubd.system.Settings; import live.page.hubd.system.db.Db; import live.page.hubd.system.db.utils.AggregateUtils; import live.page.hubd.system.db.utils.Aggregator; import live.page.hubd.system.db.utils.Pipeline; import live.page.hubd.system.db.utils.paginer.Paginer; import live.page.hubd.system.json.Json; import live.page.hubd.system.sessions.Users; import live.page.hubd.system.socket.SocketPusher; import live.page.hubd.system.utils.Fx; import org.bson.BsonUndefined; import org.bson.conversions.Bson; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; public class NoticesView { public final static Aggregator grouper = new Aggregator("ids", "count", "date", "first", "read", "title", "message", "url", "icon", "channel", "type", "devices"); public static Json readClick(String id) { Json notice = Db.findById("Notices", id); if (notice != null) { Db.updateMany("Notices", Filters.or(Filters.eq("_id", notice.getId()), Filters.eq("grouper", notice.getString("grouper", "00"))), new Json() .put("$set", new Json("read", new Date())) .put("$unset", new Json("delay", "")) ); if (!notice.getString("user", "").isEmpty()) { sendNoticesCount(Users.fakeId(notice.getString("user"))); } } return notice; } public static Json getNotices(Users user, String start, String device, String next_str) { Paginer paginer = new Paginer(next_str, "-date", device != null ? 40 : 10); Pipeline pipeline = new Pipeline(); List filters = new ArrayList<>(); filters.add(Filters.eq("user", user.getId())); Bson paging = paginer.getFilters(); Date date = new Date(); if (paging != null) { filters.add(paging); } else { if (start != null) { try { date = Fx.dateFormater.parse(start); } catch (Exception e) { return new Json("error", "UNKNOWN_DATE_FORMAT").put("needed", Fx.dateFormater.format(new Date(Settings.START_COUNT))); } } filters.add(Filters.lt("date", date)); } pipeline.add(Aggregates.match(Filters.and(filters))); pipeline.add(paginer.getLastSort()); pipeline.add(Aggregates.group("$channel", grouper.getGrouper( Accumulators.last("id", "$_id"), Accumulators.push("ids", "$_id"), Accumulators.sum("count", 1), Accumulators.first("subs", "$subs"), Accumulators.first("date", "$date"), Accumulators.last("first", "$date"), Accumulators.push("read", new Json("$cond", new Json() .put("if", new Json("$eq", Arrays.asList("$read", true))) .put("then", true) .put("else", false) ) ) ) )); pipeline.add(paginer.getFirstSort()); pipeline.add(paginer.getLimit()); pipeline.add(Aggregates.lookup("Subs", "subs", "_id", "subs")); if (device != null) { pipeline.add(Aggregates.unwind("$subs", new UnwindOptions().preserveNullAndEmptyArrays(true))); pipeline.add(Aggregates.match( Filters.or( Filters.eq("subs.device", device), Filters.eq("subs.device", null) ) )); pipeline.add(Aggregates.addFields(new Field<>("_id", "$id"))); } else { pipeline.add(Aggregates.addFields( new Field<>("_id", "$id"), new Field<>("read", new Json("$cond", new Json() .put("if", new Json("$eq", Arrays.asList(new Json("$size", "$read"), 0))) .put("then", false) .put("else", new Json("$allElementsTrue", "$read")) )), new Field<>("devices", new Json("$map", new Json("input", "$subs") .put("as", "subs") .put("in", new Json("$cond", new Json() .put("if", new Json("$eq", Arrays.asList("$$subs.device", new BsonUndefined()))) .put("then", "$$REMOVE") .put("else", "$$subs.device") ) ) ) ))); } pipeline.add(Aggregates.addFields(new Field<>("count", new Json("$cond", new Json().put("if", AggregateUtils.nullOrUndefined("$count")).put("then", 0).put("else", "$count")) ))); Json facet = new Json(); Pipeline rootPipeline = new Pipeline(); rootPipeline.add(new Json("$lookup", new Json().put("from", "Notices").put("pipeline", pipeline).put("as", "result"))); rootPipeline.add(Aggregates.unwind("$result")); rootPipeline.add(Aggregates.replaceRoot("$result")); facet.put("result", rootPipeline); if (!NoticesExtender.extenders.isEmpty()) { for (NoticesExtender extender : NoticesExtender.extenders) { Pipeline extenderPipeline = new Pipeline(); Json lookup = new Json().put("from", extender.getCollection()).put("pipeline", extender.getPipeline(user, date, paginer)).put("as", "result"); extenderPipeline.add(new Json("$lookup", lookup)); extenderPipeline.add(Aggregates.unwind("$result")); extenderPipeline.add(Aggregates.replaceRoot("$result")); facet.put(extender.key(), extenderPipeline); } } Pipeline facetPipeline = new Pipeline(); facetPipeline.add(Aggregates.limit(1)); facetPipeline.add(new Json("$facet", facet)); List arrays = new ArrayList<>(); for (String keyFacet : facet.keyList()) { arrays.add("$" + keyFacet); } if (!arrays.isEmpty()) { facetPipeline.add(Aggregates.project(new Json().put("result", new Json("$concatArrays", arrays)))); } facetPipeline.add(Aggregates.unwind("$result")); facetPipeline.add(Aggregates.replaceRoot("$result")); facetPipeline.add(paginer.getFirstSort()); facetPipeline.add(paginer.getLimit()); facetPipeline.add(Aggregates.project(grouper.getProjectionOrder())); facetPipeline.add(paginer.getLastSort()); Json notices = paginer.getResult("Notices", facetPipeline); if (notices != null) { List result = notices.getListJson("result"); if (!result.isEmpty()) { List ids = new ArrayList<>(); for (Json item : result) { if (item.getList("ids") != null) { ids.addAll(item.getList("ids")); } else { ids.add(item.getId()); } } receive(user, ids); } } return notices; } private static void receive(Users user, List ids) { boolean notify = false; for (NoticesExtender extender : NoticesExtender.extenders) { notify = extender.receive(user, ids) || notify; } notify = Db.updateMany("Notices", Filters.in("_id", ids), new Json("$set", new Json("received", true))).getModifiedCount() > 0 || notify; if (notify) { sendNoticesCount(user); } } public static Json read(Users user, Json data) { if (user == null || user.isAnonymous()) { return new Json("error", "PLEASE_LOGIN"); } long count = 0; for (NoticesExtender extender : NoticesExtender.extenders) { count += extender.read(user, data); } Json rez = new Json("ok", false); if (data.getBoolean("readAll", false)) { rez.put("ok", true); rez.put("count", Db.updateMany("Notices", Filters.and( Filters.eq("user", user.getId()), Filters.eq("read", null) ), new Json().put("$set", new Json("read", true)) ).getModifiedCount() + count); } else if (data.containsKey("id")) { rez.put("ok", Db.updateOne("Notices", Filters.and( Filters.eq("user", user.getId()), Filters.eq("_id", data.getId()) ), new Json().put("$set", new Json("read", true)) )); } else if (data.containsKey("ids")) { rez.put("ok", true); rez.put("count", Db.updateMany("Notices", Filters.and(Filters.eq("user", user.getId()), Filters.in("_id", data.getList("ids"))), new Json().put("$set", new Json("read", true)) ).getModifiedCount() + count); } return rez; } public static Json delete(Users user, Json data) { Bson filter; if (data.getId() != null) { filter = Filters.and(Filters.eq("user", user.getId()), Filters.eq("_id", data.getId())); } else if (data.getList("ids", String.class) != null) { filter = Filters.and(Filters.eq("user", user.getId()), Filters.in("_id", data.getList("ids", String.class))); } else { return new Json("error", "INVALID_DATA"); } long count = Db.deleteMany("Notices", filter).getDeletedCount(); for (NoticesExtender extender : NoticesExtender.extenders) { count += extender.delete(user, data); } return new Json("ok", true).put("count", count); } public static String countInfo(Users user) { long count = Db.count("Notices", Filters.and( Filters.eq("user", user.getId()), Filters.lt("date", new Date()), Filters.eq("received", null) ), 100); for (NoticesExtender extender : NoticesExtender.extenders) { if (count >= 100) { break; } count += extender.count(user); } return count >= 100 ? "99+" : count + ""; } public static void sendNoticesCount(Users user) { if (user != null && !user.isAnonymous()) { SocketPusher.send("user", user.getId(), new Json("action", "notices").put("notices", NoticesView.countInfo(user))); } } }