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.
/*
* 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)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment