feat(platform): forum tags module, palette, filter, and createForumPost tags

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-21 21:34:42 -04:00
co-authored by Cursor
parent 6eca466781
commit 165f42e51b
2 changed files with 84 additions and 4 deletions
+83 -4
View File
@@ -21,6 +21,7 @@ const { BotEventFanout, BOT_EVENTS } = require('pearcord-bot-events')
const { INTENTS } = require('pearcord-bot-sdk')
const { BotRateLimits } = require('pearcord-bot-limits')
const { PearcordStepUp } = require('pearcord-step-up')
const { PearcordForum } = require('pearcord-forum')
const {
createInstallToken,
verifyInstallToken,
@@ -204,6 +205,9 @@ class PearcordPlatform extends EventEmitter {
userId: user.id
})
await this.stepUp.ready()
this.forum = new PearcordForum({ storagePath: this.storagePath })
await this.forum.ready()
this._forumTagFilter = null
this.guilds = await this.listGuilds()
await this._joinDiscoveryMesh()
await this._joinContactsMesh()
@@ -707,6 +711,7 @@ class PearcordPlatform extends EventEmitter {
this.emit('link-embed', p)
})
guildInstance.on('channel-update', (ch) => this.emit('channel-update', ch))
guildInstance.on('forum-post-tags', (p) => this._onForumPostTagsGossip(p))
guildInstance.setAttachmentProvider(async (attachmentId) => {
const row = await this.attachments?.get(attachmentId)
if (!row) throw new Error('attachment not found')
@@ -715,6 +720,51 @@ class PearcordPlatform extends EventEmitter {
})
}
async _onForumPostTagsGossip (payload) {
if (!payload?.guildId || !payload?.threadId || !this.forum) return
const tags = await this.forum.setPostTags(
payload.guildId,
payload.threadId,
payload.tags || []
)
this.emit('forum-tags', { guildId: payload.guildId, threadId: payload.threadId, tags })
}
setForumTagFilter (tag) {
const t = String(tag || '').trim().toLowerCase()
this._forumTagFilter = t || null
}
async setForumChannelPalette (channelId, tags) {
if (!this.guild?.guild || !this.forum) throw new Error('no guild')
const roles = await this._memberRoles()
if (!roleHasPermission(roles, PERMISSION.MANAGE_CHANNELS)) {
throw new Error('no permission to edit forum tags')
}
const ch = await this.db.get(COLLECTIONS.CHANNELS, {
guildId: this.guild.guild.id,
id: channelId
})
if (!ch || !isForumChannel(ch)) throw new Error('not a forum channel')
const topic = this.forum.formatPaletteTopic(tags)
const updated = await this.guild.updateChannel({ ...ch, topic })
this.guild.gossipChannelUpdate(updated)
this.emit('channel-update', updated)
return { channelId, palette: this.forum.parsePaletteFromTopic(topic) }
}
async _enrichForumPosts (posts, guildId, forumChannel) {
if (!this.forum || !posts?.length) return posts
const out = []
for (const p of posts) {
const tags = await this.forum.getPostTags(guildId, p.id)
out.push({ ...p, tags })
}
const filter = this._forumTagFilter
if (!filter) return out
return out.filter((p) => (p.tags || []).includes(filter))
}
async _onKickGossip (payload) {
const user = this.identity.user
if (user && payload.userId === user.id) {
@@ -1975,7 +2025,7 @@ class PearcordPlatform extends EventEmitter {
return channel
}
async createForumPost ({ title, content }) {
async createForumPost ({ title, content, tags }) {
if (!this.guild?.guild || !this.activeChannelId) throw new Error('no active forum channel')
const forum = await this.db.get(COLLECTIONS.CHANNELS, {
guildId: this.guild.guild.id,
@@ -1996,12 +2046,25 @@ class PearcordPlatform extends EventEmitter {
const message = await this.sendMessage(body)
const merged = await this.guild.setThreadRootMessage(thread.id, message.id)
this.guild.gossipChannelUpdate(merged)
const guildId = this.guild.guild.id
const palette = this.forum.parsePaletteFromTopic(forum.topic)
const postTags = this.forum.normalizePostTags(
(tags || []).filter((t) => !palette.length || palette.includes(t))
)
if (postTags.length) {
await this.forum.setPostTags(guildId, thread.id, postTags)
this.guild.gossipForumPostTags({
guildId,
threadId: thread.id,
tags: postTags
})
}
await this._audit('forum.post.create', {
guildId: this.guild.guild.id,
guildId,
targetId: thread.id
})
this.emit('channel', merged)
return { thread: merged, message }
return { thread: { ...merged, tags: postTags }, message }
}
async createThread ({ messageId, name }) {
@@ -2372,10 +2435,23 @@ class PearcordPlatform extends EventEmitter {
threadMessageCounts[ch.id] = rows.length
}
const activeChannel = channels.find((c) => c.id === this.activeChannelId) || null
const forumPosts =
let forumPosts =
activeChannel && isForumChannel(activeChannel)
? sortForumPosts(threadsByParent[activeChannel.id] || [])
: []
let forumPaletteTags = []
let forumUsedTags = []
if (activeChannel && isForumChannel(activeChannel) && guild) {
forumPaletteTags = this.forum
? this.forum.parsePaletteFromTopic(activeChannel.topic)
: []
forumPosts = await this._enrichForumPosts(
forumPosts,
guild.id,
activeChannel
)
forumUsedTags = this.forum ? this.forum.collectUsedTags(forumPosts) : []
}
const channelMeta = {}
if (user) {
const alertRows = await this.db.find(COLLECTIONS.MENTION_ALERTS, { userId: user.id })
@@ -2509,6 +2585,9 @@ class PearcordPlatform extends EventEmitter {
threadMessageCounts,
threadTypingByParent,
forumPosts,
forumPaletteTags,
forumUsedTags,
forumTagFilter: this._forumTagFilter || null,
activeChannel,
needsGuild: this.onboarded && !this.guilds.length && this.mode !== 'dm',
guildUnread,
+1
View File
@@ -34,6 +34,7 @@
"pearcord-settings": "git+https://git.ssh.surf/pearcord/pearcord-settings.git#main",
"pearcord-device-sync": "git+https://git.ssh.surf/pearcord/pearcord-device-sync.git#main",
"pearcord-step-up": "git+https://git.ssh.surf/pearcord/pearcord-step-up.git#main",
"pearcord-forum": "git+https://git.ssh.surf/pearcord/pearcord-forum.git#main",
"hyperswarm": "^4.11.6",
"pearcord-shared": "git+https://git.ssh.surf/pearcord/pearcord-shared.git#main"
}