Skip to content

Instantly share code, notes, and snippets.

@pagetronic
Created October 16, 2025 14:32
Show Gist options
  • Save pagetronic/d17cb35ddf48c9535745a46b79e05ad7 to your computer and use it in GitHub Desktop.
Save pagetronic/d17cb35ddf48c9535745a46b79e05ad7 to your computer and use it in GitHub Desktop.

Revisions

  1. pagetronic created this gist Oct 16, 2025.
    285 changes: 285 additions & 0 deletions NoticesView.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,285 @@
    /*
    * 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<Bson> 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<String> 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<Json> result = notices.getListJson("result");
    if (!result.isEmpty()) {
    List<String> 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<String> 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)));
    }
    }

    }