mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
docs: packages,operations,lua (3 files)
This commit is contained in:
@@ -15,12 +15,15 @@ qt_add_executable(dbal-qml
|
||||
main.cpp
|
||||
src/PackageRegistry.cpp
|
||||
src/ModPlayer.cpp
|
||||
src/DBALClient.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(dbal-qml
|
||||
URI DBALObservatory
|
||||
VERSION 1.0
|
||||
QML_FILES FrontPage.qml
|
||||
QML_FILES
|
||||
FrontPage.qml
|
||||
qmllib/dbal/DBALProvider.qml
|
||||
)
|
||||
|
||||
target_link_libraries(dbal-qml PRIVATE Qt6::Core Qt6::Gui Qt6::Quick cpr::cpr libopenmpt::libopenmpt)
|
||||
|
||||
357
packages/forum_forge/seed/scripts/db/operations.lua
Normal file
357
packages/forum_forge/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,357 @@
|
||||
-- forum_forge/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for Forum entities (Category, Thread, Post)
|
||||
-- @module forum_forge.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- CATEGORY OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ForumCategoryCreateParams
|
||||
---@field tenantId string
|
||||
---@field name string
|
||||
---@field slug string
|
||||
---@field description string|nil
|
||||
---@field icon string|nil
|
||||
---@field color string|nil
|
||||
---@field parentId string|nil
|
||||
---@field minLevel number|nil
|
||||
|
||||
---Create a new forum category
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ForumCategoryCreateParams
|
||||
---@return table Created category
|
||||
function M.createCategory(dbal, params)
|
||||
-- Get next sort order
|
||||
local existing = dbal:list('ForumCategory', {
|
||||
where = { tenantId = params.tenantId },
|
||||
orderBy = { sortOrder = 'desc' },
|
||||
take = 1,
|
||||
})
|
||||
|
||||
local maxOrder = 0
|
||||
if existing.items and #existing.items > 0 then
|
||||
maxOrder = existing.items[1].sortOrder or 0
|
||||
end
|
||||
|
||||
return dbal:create('ForumCategory', {
|
||||
tenantId = params.tenantId,
|
||||
name = params.name,
|
||||
slug = params.slug,
|
||||
description = params.description,
|
||||
icon = params.icon,
|
||||
color = params.color,
|
||||
parentId = params.parentId,
|
||||
sortOrder = maxOrder + 1,
|
||||
minLevel = params.minLevel or 0,
|
||||
threadCount = 0,
|
||||
postCount = 0,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---List categories
|
||||
---@param dbal table DBAL client instance
|
||||
---@param tenantId string
|
||||
---@param parentId string|nil Filter by parent (nil for root)
|
||||
---@return table[] Categories
|
||||
function M.listCategories(dbal, tenantId, parentId)
|
||||
local where = { tenantId = tenantId }
|
||||
if parentId then
|
||||
where.parentId = parentId
|
||||
end
|
||||
|
||||
local result = dbal:list('ForumCategory', {
|
||||
where = where,
|
||||
orderBy = { sortOrder = 'asc' },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Update category
|
||||
---@param dbal table
|
||||
---@param categoryId string
|
||||
---@param updates table
|
||||
---@return table Updated category
|
||||
function M.updateCategory(dbal, categoryId, updates)
|
||||
updates.updatedAt = os.time() * 1000
|
||||
return dbal:update('ForumCategory', categoryId, updates)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- THREAD OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ForumThreadCreateParams
|
||||
---@field tenantId string
|
||||
---@field categoryId string
|
||||
---@field authorId string
|
||||
---@field authorName string
|
||||
---@field title string
|
||||
---@field tags table|nil Array of tag strings
|
||||
---@field isPinned boolean|nil
|
||||
---@field isLocked boolean|nil
|
||||
|
||||
---Create a new thread
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ForumThreadCreateParams
|
||||
---@return table Created thread
|
||||
function M.createThread(dbal, params)
|
||||
local thread = dbal:create('ForumThread', {
|
||||
tenantId = params.tenantId,
|
||||
categoryId = params.categoryId,
|
||||
authorId = params.authorId,
|
||||
authorName = params.authorName,
|
||||
title = params.title,
|
||||
slug = M._slugify(params.title),
|
||||
tags = params.tags and json.encode(params.tags) or '[]',
|
||||
isPinned = params.isPinned or false,
|
||||
isLocked = params.isLocked or false,
|
||||
viewCount = 0,
|
||||
replyCount = 0,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
lastPostAt = os.time() * 1000,
|
||||
lastPostAuthorId = params.authorId,
|
||||
lastPostAuthorName = params.authorName,
|
||||
})
|
||||
|
||||
-- Increment category thread count
|
||||
local category = dbal:read('ForumCategory', params.categoryId)
|
||||
if category then
|
||||
dbal:update('ForumCategory', params.categoryId, {
|
||||
threadCount = (category.threadCount or 0) + 1,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return thread
|
||||
end
|
||||
|
||||
---List threads in a category
|
||||
---@param dbal table DBAL client instance
|
||||
---@param categoryId string
|
||||
---@param take number|nil
|
||||
---@param skip number|nil
|
||||
---@return table List result
|
||||
function M.listThreads(dbal, categoryId, take, skip)
|
||||
return dbal:list('ForumThread', {
|
||||
where = { categoryId = categoryId },
|
||||
orderBy = { isPinned = 'desc', lastPostAt = 'desc' },
|
||||
take = take or 20,
|
||||
skip = skip or 0,
|
||||
})
|
||||
end
|
||||
|
||||
---Get thread by ID
|
||||
---@param dbal table DBAL client instance
|
||||
---@param threadId string
|
||||
---@param incrementView boolean|nil Increment view count
|
||||
---@return table|nil Thread
|
||||
function M.getThread(dbal, threadId, incrementView)
|
||||
local thread = dbal:read('ForumThread', threadId)
|
||||
|
||||
if thread and incrementView then
|
||||
dbal:update('ForumThread', threadId, {
|
||||
viewCount = (thread.viewCount or 0) + 1,
|
||||
})
|
||||
thread.viewCount = (thread.viewCount or 0) + 1
|
||||
end
|
||||
|
||||
return thread
|
||||
end
|
||||
|
||||
---Update thread
|
||||
---@param dbal table
|
||||
---@param threadId string
|
||||
---@param updates table
|
||||
---@return table Updated thread
|
||||
function M.updateThread(dbal, threadId, updates)
|
||||
updates.updatedAt = os.time() * 1000
|
||||
return dbal:update('ForumThread', threadId, updates)
|
||||
end
|
||||
|
||||
---Pin/unpin a thread
|
||||
---@param dbal table
|
||||
---@param threadId string
|
||||
---@param isPinned boolean
|
||||
function M.pinThread(dbal, threadId, isPinned)
|
||||
return M.updateThread(dbal, threadId, { isPinned = isPinned })
|
||||
end
|
||||
|
||||
---Lock/unlock a thread
|
||||
---@param dbal table
|
||||
---@param threadId string
|
||||
---@param isLocked boolean
|
||||
function M.lockThread(dbal, threadId, isLocked)
|
||||
return M.updateThread(dbal, threadId, { isLocked = isLocked })
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- POST OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ForumPostCreateParams
|
||||
---@field tenantId string
|
||||
---@field threadId string
|
||||
---@field authorId string
|
||||
---@field authorName string
|
||||
---@field content string
|
||||
---@field replyToId string|nil
|
||||
|
||||
---Create a new post (reply)
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ForumPostCreateParams
|
||||
---@return table Created post
|
||||
function M.createPost(dbal, params)
|
||||
local thread = dbal:read('ForumThread', params.threadId)
|
||||
if not thread then
|
||||
error('Thread not found: ' .. params.threadId)
|
||||
end
|
||||
|
||||
if thread.isLocked then
|
||||
error('Thread is locked')
|
||||
end
|
||||
|
||||
local post = dbal:create('ForumPost', {
|
||||
tenantId = params.tenantId,
|
||||
threadId = params.threadId,
|
||||
authorId = params.authorId,
|
||||
authorName = params.authorName,
|
||||
content = params.content,
|
||||
replyToId = params.replyToId,
|
||||
isEdited = false,
|
||||
likeCount = 0,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
|
||||
-- Update thread stats
|
||||
dbal:update('ForumThread', params.threadId, {
|
||||
replyCount = (thread.replyCount or 0) + 1,
|
||||
lastPostAt = os.time() * 1000,
|
||||
lastPostAuthorId = params.authorId,
|
||||
lastPostAuthorName = params.authorName,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
|
||||
-- Update category post count
|
||||
local category = dbal:read('ForumCategory', thread.categoryId)
|
||||
if category then
|
||||
dbal:update('ForumCategory', thread.categoryId, {
|
||||
postCount = (category.postCount or 0) + 1,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return post
|
||||
end
|
||||
|
||||
---List posts in a thread
|
||||
---@param dbal table DBAL client instance
|
||||
---@param threadId string
|
||||
---@param take number|nil
|
||||
---@param skip number|nil
|
||||
---@return table List result
|
||||
function M.listPosts(dbal, threadId, take, skip)
|
||||
return dbal:list('ForumPost', {
|
||||
where = { threadId = threadId },
|
||||
orderBy = { createdAt = 'asc' },
|
||||
take = take or 50,
|
||||
skip = skip or 0,
|
||||
})
|
||||
end
|
||||
|
||||
---Update post content
|
||||
---@param dbal table
|
||||
---@param postId string
|
||||
---@param content string
|
||||
---@return table Updated post
|
||||
function M.updatePost(dbal, postId, content)
|
||||
return dbal:update('ForumPost', postId, {
|
||||
content = content,
|
||||
isEdited = true,
|
||||
editedAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Like a post
|
||||
---@param dbal table
|
||||
---@param postId string
|
||||
---@return table Updated post
|
||||
function M.likePost(dbal, postId)
|
||||
local post = dbal:read('ForumPost', postId)
|
||||
if post then
|
||||
return dbal:update('ForumPost', postId, {
|
||||
likeCount = (post.likeCount or 0) + 1,
|
||||
})
|
||||
end
|
||||
return post
|
||||
end
|
||||
|
||||
---Delete a post (soft delete by clearing content)
|
||||
---@param dbal table
|
||||
---@param postId string
|
||||
---@param deletedBy string Username who deleted
|
||||
---@return table Updated post
|
||||
function M.deletePost(dbal, postId, deletedBy)
|
||||
return dbal:update('ForumPost', postId, {
|
||||
content = '[Deleted by ' .. deletedBy .. ']',
|
||||
isEdited = true,
|
||||
editedAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- UTILITY FUNCTIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Generate a URL-safe slug from text
|
||||
---@param text string
|
||||
---@return string Slug
|
||||
function M._slugify(text)
|
||||
local slug = text:lower()
|
||||
slug = slug:gsub('[^%w%s-]', '')
|
||||
slug = slug:gsub('%s+', '-')
|
||||
slug = slug:gsub('-+', '-')
|
||||
slug = slug:gsub('^-', ''):gsub('-$', '')
|
||||
return slug:sub(1, 100)
|
||||
end
|
||||
|
||||
---Search threads by title
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param query string
|
||||
---@param take number|nil
|
||||
---@return table[] Matching threads
|
||||
function M.searchThreads(dbal, tenantId, query, take)
|
||||
-- Basic implementation - fetch and filter
|
||||
-- TODO: Implement proper full-text search via DBAL
|
||||
local result = dbal:list('ForumThread', {
|
||||
where = { tenantId = tenantId },
|
||||
take = 1000,
|
||||
})
|
||||
|
||||
local matches = {}
|
||||
local lowerQuery = query:lower()
|
||||
|
||||
for _, thread in ipairs(result.items or {}) do
|
||||
if thread.title:lower():find(lowerQuery, 1, true) then
|
||||
table.insert(matches, thread)
|
||||
if #matches >= (take or 20) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
return M
|
||||
417
packages/irc_webchat/seed/scripts/db/operations.lua
Normal file
417
packages/irc_webchat/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,417 @@
|
||||
-- irc_webchat/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for IRC entities (Channel, Message, Membership)
|
||||
-- @module irc_webchat.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- CHANNEL OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class IRCChannelCreateParams
|
||||
---@field tenantId string
|
||||
---@field name string Must start with #
|
||||
---@field displayName string|nil
|
||||
---@field description string|nil
|
||||
---@field topic string|nil
|
||||
---@field minLevel number|nil
|
||||
---@field creatorId string
|
||||
|
||||
---Create a new IRC channel
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params IRCChannelCreateParams
|
||||
---@return table Created channel
|
||||
function M.createChannel(dbal, params)
|
||||
-- Validate channel name starts with #
|
||||
local name = params.name
|
||||
if name:sub(1, 1) ~= '#' then
|
||||
name = '#' .. name
|
||||
end
|
||||
|
||||
-- Check for duplicate channel name
|
||||
local existing = dbal:findFirst('IRCChannel', {
|
||||
where = { tenantId = params.tenantId, name = name },
|
||||
})
|
||||
|
||||
if existing then
|
||||
error('Channel already exists: ' .. name)
|
||||
end
|
||||
|
||||
return dbal:create('IRCChannel', {
|
||||
tenantId = params.tenantId,
|
||||
name = name,
|
||||
displayName = params.displayName or name:sub(2),
|
||||
description = params.description,
|
||||
topic = params.topic or 'Welcome to ' .. name,
|
||||
minLevel = params.minLevel or 0,
|
||||
isPrivate = false,
|
||||
isArchived = false,
|
||||
creatorId = params.creatorId,
|
||||
memberCount = 0,
|
||||
messageCount = 0,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
lastActivityAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get channel by name
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param name string
|
||||
---@return table|nil Channel
|
||||
function M.getChannelByName(dbal, tenantId, name)
|
||||
if name:sub(1, 1) ~= '#' then
|
||||
name = '#' .. name
|
||||
end
|
||||
|
||||
return dbal:findFirst('IRCChannel', {
|
||||
where = { tenantId = tenantId, name = name },
|
||||
})
|
||||
end
|
||||
|
||||
---List all channels
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param includeArchived boolean|nil
|
||||
---@return table[] Channels
|
||||
function M.listChannels(dbal, tenantId, includeArchived)
|
||||
local result = dbal:list('IRCChannel', {
|
||||
where = { tenantId = tenantId },
|
||||
orderBy = { memberCount = 'desc' },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
local channels = result.items or {}
|
||||
|
||||
if not includeArchived then
|
||||
local active = {}
|
||||
for _, ch in ipairs(channels) do
|
||||
if not ch.isArchived then
|
||||
table.insert(active, ch)
|
||||
end
|
||||
end
|
||||
channels = active
|
||||
end
|
||||
|
||||
return channels
|
||||
end
|
||||
|
||||
---Update channel topic
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param topic string
|
||||
---@param userId string Who set the topic
|
||||
---@return table Updated channel
|
||||
function M.setTopic(dbal, channelId, topic, userId)
|
||||
return dbal:update('IRCChannel', channelId, {
|
||||
topic = topic,
|
||||
topicSetBy = userId,
|
||||
topicSetAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Archive a channel
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
function M.archiveChannel(dbal, channelId)
|
||||
return dbal:update('IRCChannel', channelId, {
|
||||
isArchived = true,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- MESSAGE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class IRCMessageCreateParams
|
||||
---@field tenantId string
|
||||
---@field channelId string
|
||||
---@field userId string
|
||||
---@field username string
|
||||
---@field displayName string|nil
|
||||
---@field type string message|join|part|action|notice|system
|
||||
---@field content string
|
||||
---@field replyToId string|nil
|
||||
|
||||
---Send a message to a channel
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params IRCMessageCreateParams
|
||||
---@return table Created message
|
||||
function M.sendMessage(dbal, params)
|
||||
local message = dbal:create('IRCMessage', {
|
||||
tenantId = params.tenantId,
|
||||
channelId = params.channelId,
|
||||
userId = params.userId,
|
||||
username = params.username,
|
||||
displayName = params.displayName or params.username,
|
||||
type = params.type or 'message',
|
||||
content = params.content,
|
||||
replyToId = params.replyToId,
|
||||
timestamp = os.time() * 1000,
|
||||
})
|
||||
|
||||
-- Update channel stats
|
||||
local channel = dbal:read('IRCChannel', params.channelId)
|
||||
if channel then
|
||||
dbal:update('IRCChannel', params.channelId, {
|
||||
messageCount = (channel.messageCount or 0) + 1,
|
||||
lastActivityAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return message
|
||||
end
|
||||
|
||||
---Get channel messages (most recent first)
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param take number|nil
|
||||
---@param before number|nil Timestamp - get messages before this time
|
||||
---@return table[] Messages
|
||||
function M.getMessages(dbal, channelId, take, before)
|
||||
local result = dbal:list('IRCMessage', {
|
||||
where = { channelId = channelId },
|
||||
orderBy = { timestamp = 'desc' },
|
||||
take = take or 50,
|
||||
})
|
||||
|
||||
local messages = result.items or {}
|
||||
|
||||
-- Filter by timestamp if specified
|
||||
if before then
|
||||
local filtered = {}
|
||||
for _, msg in ipairs(messages) do
|
||||
if msg.timestamp < before then
|
||||
table.insert(filtered, msg)
|
||||
end
|
||||
end
|
||||
messages = filtered
|
||||
end
|
||||
|
||||
-- Reverse to get chronological order for display
|
||||
local reversed = {}
|
||||
for i = #messages, 1, -1 do
|
||||
table.insert(reversed, messages[i])
|
||||
end
|
||||
|
||||
return reversed
|
||||
end
|
||||
|
||||
---Send a system message
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param channelId string
|
||||
---@param content string
|
||||
function M.sendSystemMessage(dbal, tenantId, channelId, content)
|
||||
return M.sendMessage(dbal, {
|
||||
tenantId = tenantId,
|
||||
channelId = channelId,
|
||||
userId = 'system',
|
||||
username = '*system*',
|
||||
type = 'system',
|
||||
content = content,
|
||||
})
|
||||
end
|
||||
|
||||
---Delete a message (mark as deleted)
|
||||
---@param dbal table
|
||||
---@param messageId string
|
||||
---@param deletedBy string
|
||||
function M.deleteMessage(dbal, messageId, deletedBy)
|
||||
return dbal:update('IRCMessage', messageId, {
|
||||
content = '[deleted by ' .. deletedBy .. ']',
|
||||
type = 'system',
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- MEMBERSHIP OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class IRCMembershipParams
|
||||
---@field tenantId string
|
||||
---@field channelId string
|
||||
---@field userId string
|
||||
---@field username string
|
||||
---@field role string owner|operator|voiced|member
|
||||
|
||||
---Join a channel
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params IRCMembershipParams
|
||||
---@return table Membership record
|
||||
function M.joinChannel(dbal, params)
|
||||
-- Check if already a member
|
||||
local existing = dbal:findFirst('IRCMembership', {
|
||||
where = {
|
||||
channelId = params.channelId,
|
||||
userId = params.userId,
|
||||
},
|
||||
})
|
||||
|
||||
if existing then
|
||||
-- Update last seen
|
||||
return dbal:update('IRCMembership', existing.id, {
|
||||
isOnline = true,
|
||||
lastSeenAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
local membership = dbal:create('IRCMembership', {
|
||||
tenantId = params.tenantId,
|
||||
channelId = params.channelId,
|
||||
userId = params.userId,
|
||||
username = params.username,
|
||||
role = params.role or 'member',
|
||||
isOnline = true,
|
||||
joinedAt = os.time() * 1000,
|
||||
lastSeenAt = os.time() * 1000,
|
||||
})
|
||||
|
||||
-- Update channel member count
|
||||
local channel = dbal:read('IRCChannel', params.channelId)
|
||||
if channel then
|
||||
dbal:update('IRCChannel', params.channelId, {
|
||||
memberCount = (channel.memberCount or 0) + 1,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
-- Send join message
|
||||
M.sendMessage(dbal, {
|
||||
tenantId = params.tenantId,
|
||||
channelId = params.channelId,
|
||||
userId = params.userId,
|
||||
username = params.username,
|
||||
type = 'join',
|
||||
content = params.username .. ' has joined the channel',
|
||||
})
|
||||
|
||||
return membership
|
||||
end
|
||||
|
||||
---Leave a channel
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param userId string
|
||||
---@param message string|nil Part message
|
||||
function M.leaveChannel(dbal, channelId, userId, message)
|
||||
local membership = dbal:findFirst('IRCMembership', {
|
||||
where = { channelId = channelId, userId = userId },
|
||||
})
|
||||
|
||||
if not membership then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Send part message
|
||||
local channel = dbal:read('IRCChannel', channelId)
|
||||
M.sendMessage(dbal, {
|
||||
tenantId = membership.tenantId,
|
||||
channelId = channelId,
|
||||
userId = userId,
|
||||
username = membership.username,
|
||||
type = 'part',
|
||||
content = membership.username .. ' has left' .. (message and (': ' .. message) or ''),
|
||||
})
|
||||
|
||||
-- Delete membership
|
||||
dbal:delete('IRCMembership', membership.id)
|
||||
|
||||
-- Update channel member count
|
||||
if channel then
|
||||
dbal:update('IRCChannel', channelId, {
|
||||
memberCount = math.max(0, (channel.memberCount or 1) - 1),
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---Get channel members
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param onlineOnly boolean|nil
|
||||
---@return table[] Members
|
||||
function M.getMembers(dbal, channelId, onlineOnly)
|
||||
local result = dbal:list('IRCMembership', {
|
||||
where = { channelId = channelId },
|
||||
orderBy = { role = 'asc', username = 'asc' },
|
||||
take = 500,
|
||||
})
|
||||
|
||||
local members = result.items or {}
|
||||
|
||||
if onlineOnly then
|
||||
local online = {}
|
||||
for _, m in ipairs(members) do
|
||||
if m.isOnline then
|
||||
table.insert(online, m)
|
||||
end
|
||||
end
|
||||
members = online
|
||||
end
|
||||
|
||||
return members
|
||||
end
|
||||
|
||||
---Set user's online status
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param userId string
|
||||
---@param isOnline boolean
|
||||
function M.setOnlineStatus(dbal, channelId, userId, isOnline)
|
||||
local membership = dbal:findFirst('IRCMembership', {
|
||||
where = { channelId = channelId, userId = userId },
|
||||
})
|
||||
|
||||
if membership then
|
||||
dbal:update('IRCMembership', membership.id, {
|
||||
isOnline = isOnline,
|
||||
lastSeenAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
---Update user role in channel
|
||||
---@param dbal table
|
||||
---@param channelId string
|
||||
---@param userId string
|
||||
---@param role string owner|operator|voiced|member
|
||||
function M.setRole(dbal, channelId, userId, role)
|
||||
local membership = dbal:findFirst('IRCMembership', {
|
||||
where = { channelId = channelId, userId = userId },
|
||||
})
|
||||
|
||||
if membership then
|
||||
dbal:update('IRCMembership', membership.id, { role = role })
|
||||
end
|
||||
end
|
||||
|
||||
---Get channels a user is in
|
||||
---@param dbal table
|
||||
---@param userId string
|
||||
---@return table[] Channels
|
||||
function M.getUserChannels(dbal, userId)
|
||||
local memberships = dbal:list('IRCMembership', {
|
||||
where = { userId = userId },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
local channels = {}
|
||||
for _, m in ipairs(memberships.items or {}) do
|
||||
local channel = dbal:read('IRCChannel', m.channelId)
|
||||
if channel and not channel.isArchived then
|
||||
table.insert(channels, channel)
|
||||
end
|
||||
end
|
||||
|
||||
return channels
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user