OverviewFilesCommitsIssuesDocsReleasesPeers

keet-cli / keet-core-4.14.4-pretty / lib / core / contract / chat.js

172 lines · javascript ref:
const e = require("b4a"),
  t = require("./registration"),
  { getMemberForDeviceKey: s, isMemberActive: i } = require("./query"),
  { KeetContractError: a } = require("./errors"),
  { insertMessageFiles: r, deleteMessageFiles: o, updateImageFile: n } = require("./avatars"),
  {
    contract: {
      hyperschema: { getEnum: l },
    },
  } = require("../../../schema/spec"),
  { chatStats: d, fileStats: c } = require("./stats"),
  g = l("@keet/room-type")
async function h(e, t, s, i) {
  const a = await e.get("@keet/threads", { id: 0 }),
    r = {
      id: { thread: 0, index: a.count },
      oplog: t,
      clock: a.stats.chat.clock,
      timestamp: i,
      event: s,
      status: { isEdited: !1, isPinned: !1, isDeleted: !1 },
    }
  ;(await e.insert("@keet/chat", r), await d(e, a, r))
}
async function p({ message: e, header: t }, { db: o, blobs: n, writer: l }) {
  let [c, h, p, w, k, m] = await Promise.all([
    s(o, l.key),
    o.get("@keet/threads", { id: 0 }),
    e.parent ? o.get("@keet/threads-by-parent", { oplog: e.parent }) : null,
    e.parent ? o.get("@keet/chat-by-message-id", { oplog: e.parent }) : null,
    e.replyTo ? o.get("@keet/chat-by-message-id", { oplog: e.replyTo }) : null,
    o.get("@keet/system-digest"),
  ])
  if (!i(c)) throw a.INACTIVE_MEMBER()
  if (c.status.isMuted) throw a.WRITER_IS_MUTED()
  const y = m.settings.roomType === g.Broadcast || m.settings.isAppendingDisabled
  if (!c.status.isModerator && y) throw a.MODERATORS_ONLY()
  if (e.parent && !w) throw a.PARENT_MSG_INVALID()
  if (e.replyTo && !k) throw a.REPLYTO_MSG_INVALID()
  if ((e.parent || (p = h), e.event?.callMissed)) {
    const e = await o.get("@keet/chat", { id: { thread: p.id, index: p.count - 1 } })
    if (e && e.event.callMissed) throw a.NO_DUPLICATE_CALL_EVENTS()
  }
  if (m.settings.isAttachmentsDisabled && T(e)) throw a.FILE_ATTACHMENTS_DISABLED()
  if (m.settings.isLinksDisabled && _(e)) throw a.LINKS_DISABLED()
  const E = h.stats.files.clock
  e.files = await r({ primaryThread: h, clock: E, message: e, blobs: n, db: o, oplog: l })
  const f = {
    id: { thread: p.id, index: p.count },
    oplog: l,
    clock: h.stats.chat.clock,
    timestamp: t.timestamp,
    message: e,
    status: { isEdited: !1, isPinned: !1, isDeleted: !1 },
    event: e.event,
  }
  ;(await o.insert("@keet/chat", f), await d(o, h, f))
}
async function w({ header: t, oplog: n, message: l }, { db: c, blobs: g, writer: h }) {
  const [p, w, k, m, y, E] = await Promise.all([
    s(c, h.key),
    s(c, n.key),
    c.get("@keet/chat-by-message-id", { oplog: n }),
    c.get("@keet/threads", { id: 0 }),
    l.replyTo ? c.get("@keet/chat-by-message-id", { oplog: l.replyTo }) : null,
    c.get("@keet/system-digest"),
  ])
  if (!i(p)) throw a.INACTIVE_MEMBER()
  if (!k) throw a.TARGET_MSG_INVALID()
  if (!w) throw a.TARGET_MEMBER_NOT_FOUND()
  if (!e.equals(p.key, w.key)) throw a.SELF_ONLY()
  if (k.status.isDeleted) throw a.TARGET_MSG_IS_DELETED()
  if (l.replyTo && !y) throw a.REPLYTO_MSG_INVALID()
  if (E.settings.isAttachmentsDisabled && T(l)) throw a.FILE_ATTACHMENTS_DISABLED()
  if (E.settings.isLinksDisabled && _(l)) throw a.LINKS_DISABLED()
  const f = []
  ;(k.message?.files?.length && (f.push(...k.message.files), (k.message.files = [])),
    (l.files = []),
    await o({ primaryThread: m, message: k, db: c, blobs: g }))
  const u = m.stats.files.clock
  await r({ primaryThread: m, clock: u, message: l, blobs: g, db: c, oplog: h })
  const b = {
    ...k,
    message: { ...k.message, text: l.text, files: f, display: l.display },
    status: { ...k.status, isEdited: !0 },
    editedAt: t.timestamp,
  }
  ;(await c.insert("@keet/chat", b), await d(c, m, b, k))
}
async function k({ oplog: t }, { db: r, blobs: n, writer: l }) {
  const [c, g, h, p] = await Promise.all([
    s(r, l.key),
    s(r, t.key),
    r.get("@keet/chat-by-message-id", { oplog: t }),
    r.get("@keet/threads", { id: 0 }),
  ])
  if (!i(c)) throw a.INACTIVE_MEMBER()
  if (!h) throw a.TARGET_MSG_INVALID()
  if (!c.status.isModerator && !e.equals(c.key, g.key)) throw a.MODERATORS_OR_SELF_ONLY()
  await o({ primaryThread: p, message: h, db: r, blobs: n })
  const w = { ...h, message: null, status: { ...h.status, isDeleted: !0, isPinned: !1 } }
  ;(await r.insert("@keet/chat", w), await d(r, p, w, h))
  const k = await r.get("@keet/chat-label-digests", { id: h.id })
  k && (await r.insert("@keet/chat-label-digests", { ...k, isDeleted: !0 }))
}
async function m({ oplog: e, isPinned: t }, { db: r, writer: o }) {
  const [n, l, c] = await Promise.all([
    s(r, o.key),
    r.get("@keet/chat-by-message-id", { oplog: e }),
    r.get("@keet/threads", { id: 0 }),
  ])
  if (!i(n)) throw a.INACTIVE_MEMBER()
  if (!l) throw a.TARGET_MSG_INVALID()
  if (!n.status.isModerator) throw a.MODERATORS_ONLY()
  const g = { ...l, status: { ...l.status, isPinned: t } }
  ;(await r.insert("@keet/chat", g), await d(r, c, g, l))
}
async function y(
  { oplog: t, index: r, preview: o, displayType: l },
  { db: d, blobs: g, writer: h },
) {
  const [p, w, k, m] = await Promise.all([
    s(d, h.key),
    s(d, t.key),
    d.get("@keet/chat-by-message-id", { oplog: t }),
    d.get("@keet/threads", { id: 0 }),
  ])
  if (!i(p)) throw a.INACTIVE_MEMBER()
  if (!k) throw a.TARGET_MSG_INVALID()
  if (!e.equals(p.key, w.key)) throw a.SELF_ONLY()
  const y = l ? u(k, l, r) : k.message?.files,
    E = l ? 0 : r
  if (!y || y.length <= E) throw a.FILE_REFERENCE_INVALID("files is falsy or invalid index")
  const f = await d.get("@keet/files", { id: y[E] })
  if (!f) throw a.FILE_RECORD_INVALID("record is falsy")
  ;((f.file.preview = await n(g, null, o)), await d.insert("@keet/files", f), await c(d, m, f, f))
}
async function E({ length: e }, { db: t, writer: a }) {
  const [r, o] = await Promise.all([t.get("@keet/system-digest"), s(t, a.key)])
  i(o) &&
    !o.status.isMuted &&
    r.settings.roomType === g.DirectMessage &&
    (await t.insert("@keet/read-lengths", { memberKey: o.key, length: e }))
}
function f(e) {
  ;(e.add("@keet/add-chat-message", p),
    e.add("@keet/update-chat-message", w),
    e.add("@keet/remove-chat-message", k),
    e.add("@keet/pin-chat-message", m),
    e.add("@keet/add-file-preview", y),
    e.add("@keet/update-read-length", E))
}
function u(e, t, s) {
  switch (t) {
    case 1:
      return e.message.display.httpLink[s].preview.files
    case 2:
      return e.message.display.pearLink[s].preview.files
  }
}
function T(e) {
  return (
    e?.files?.length > 0 ||
    e?.display?.httpLink?.some((e) => e.preview) ||
    e?.display?.pearLink?.some((e) => e.preview)
  )
}
function _(e) {
  return e.display?.httpLink?.length > 0 || e?.display?.pearLink?.length > 0
}
module.exports = { addEvent: h, [t]: f }