mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
docs: packages,operations,lua (6 files)
This commit is contained in:
@@ -22,10 +22,10 @@
|
||||
| 9 | CSS Designer | ✅ Complete | 100% |
|
||||
| 10 | Parameterized Tests | ✅ Complete | 95% |
|
||||
| 11 | Package Validator | ✅ Complete | 100% |
|
||||
| 12 | Multi-Frontend | 🟡 In Progress | 50% |
|
||||
| 13 | E2E Verification | 🟡 In Progress | 65% |
|
||||
| 14 | Documentation | 🟡 In Progress | 60% |
|
||||
| 15 | Package Schema System | 🟡 In Progress | 80% |
|
||||
| 12 | Multi-Frontend | 🟡 In Progress | 65% |
|
||||
| 13 | E2E Verification | 🟡 In Progress | 70% |
|
||||
| 14 | Documentation | 🟡 In Progress | 65% |
|
||||
| 15 | Package Schema System | ✅ Complete | 95% |
|
||||
|
||||
---
|
||||
|
||||
@@ -94,8 +94,26 @@
|
||||
- [x] notification_center (Notification) + Lua operations
|
||||
- [x] forum_forge (ForumCategory, ForumThread, ForumPost) + Lua operations
|
||||
- [x] irc_webchat (IRCChannel, IRCMessage, IRCMembership) + Lua operations
|
||||
- [x] media_center (MediaAsset, MediaJob)
|
||||
- [x] stream_cast (StreamChannel, StreamSchedule, StreamScene)
|
||||
- [x] media_center (MediaAsset, MediaJob) + Lua operations
|
||||
- [x] stream_cast (StreamChannel, StreamSchedule, StreamScene) + Lua operations
|
||||
|
||||
### Packages with DBAL Operations (Using Core Entities)
|
||||
- [x] user_manager - User CRUD, permissions, search, bulk ops
|
||||
- [x] role_editor - Role management, user-role assignment, permissions
|
||||
- [x] workflow_editor - Workflow CRUD, execution, step logging
|
||||
- [x] codegen_studio - Project, Blueprint, Template management
|
||||
- [x] github_tools - GitHub connection, repos, webhooks, PR tracking
|
||||
- [x] smtp_config - SMTP config, email templates, email logs
|
||||
- [x] data_table - Generic CRUD helpers, table config, user preferences
|
||||
- [x] dashboard - Layout, widget, cache operations
|
||||
- [x] arcade_lobby - Game, Leaderboard, Session operations
|
||||
- [x] form_builder - Form, Field, Submission operations
|
||||
- [x] css_designer - Theme, Style Component, CSS generation
|
||||
- [x] schema_editor - Entity Schema CRUD, field/index/relation management
|
||||
- [x] code_editor - Snippets, Sessions, Revisions, Language config
|
||||
- [x] package_validator - Validation runs, issues, rules
|
||||
- [x] screenshot_analyzer - Screenshot, Analysis, Components, Colors
|
||||
- [x] social_hub - Profiles, Connections, Activity, Likes
|
||||
|
||||
### Multi-Frontend DBAL Support
|
||||
- [x] Qt6/QML DBALClient (C++ + QML provider)
|
||||
|
||||
359
packages/code_editor/seed/scripts/db/operations.lua
Normal file
359
packages/code_editor/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,359 @@
|
||||
-- code_editor/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for Code Snippets and Editor Sessions
|
||||
-- @module code_editor.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- CODE SNIPPET OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class SnippetCreateParams
|
||||
---@field tenantId string
|
||||
---@field userId string
|
||||
---@field title string
|
||||
---@field language string
|
||||
---@field code string
|
||||
---@field description string|nil
|
||||
---@field tags table[]|nil
|
||||
---@field isPublic boolean|nil
|
||||
|
||||
---Create a code snippet
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params SnippetCreateParams
|
||||
---@return table Created snippet
|
||||
function M.createSnippet(dbal, params)
|
||||
return dbal:create('CodeSnippet', {
|
||||
tenantId = params.tenantId,
|
||||
userId = params.userId,
|
||||
title = params.title,
|
||||
language = params.language,
|
||||
code = params.code,
|
||||
description = params.description,
|
||||
tags = params.tags and json.encode(params.tags) or nil,
|
||||
isPublic = params.isPublic or false,
|
||||
version = 1,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get snippet by ID
|
||||
---@param dbal table
|
||||
---@param snippetId string
|
||||
---@return table|nil Snippet
|
||||
function M.getSnippet(dbal, snippetId)
|
||||
local snippet = dbal:read('CodeSnippet', snippetId)
|
||||
if snippet and snippet.tags then
|
||||
snippet.tags = json.decode(snippet.tags)
|
||||
end
|
||||
return snippet
|
||||
end
|
||||
|
||||
---List user's snippets
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param language string|nil Filter by language
|
||||
---@return table[] Snippets
|
||||
function M.listUserSnippets(dbal, tenantId, userId, language)
|
||||
local result = dbal:list('CodeSnippet', {
|
||||
where = { tenantId = tenantId, userId = userId },
|
||||
orderBy = { updatedAt = 'desc' },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
local snippets = result.items or {}
|
||||
|
||||
if language then
|
||||
local filtered = {}
|
||||
for _, s in ipairs(snippets) do
|
||||
if s.language == language then
|
||||
table.insert(filtered, s)
|
||||
end
|
||||
end
|
||||
snippets = filtered
|
||||
end
|
||||
|
||||
return snippets
|
||||
end
|
||||
|
||||
---List public snippets
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param language string|nil
|
||||
---@param take number|nil
|
||||
---@return table[] Snippets
|
||||
function M.listPublicSnippets(dbal, tenantId, language, take)
|
||||
local result = dbal:list('CodeSnippet', {
|
||||
where = { tenantId = tenantId, isPublic = true },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 50,
|
||||
})
|
||||
|
||||
local snippets = result.items or {}
|
||||
|
||||
if language then
|
||||
local filtered = {}
|
||||
for _, s in ipairs(snippets) do
|
||||
if s.language == language then
|
||||
table.insert(filtered, s)
|
||||
end
|
||||
end
|
||||
snippets = filtered
|
||||
end
|
||||
|
||||
return snippets
|
||||
end
|
||||
|
||||
---Search snippets
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param query string
|
||||
---@param userId string|nil
|
||||
---@return table[] Matching snippets
|
||||
function M.searchSnippets(dbal, tenantId, query, userId)
|
||||
local where = { tenantId = tenantId }
|
||||
|
||||
-- Get all accessible snippets
|
||||
local result = dbal:list('CodeSnippet', {
|
||||
where = where,
|
||||
take = 1000,
|
||||
})
|
||||
|
||||
local lowerQuery = query:lower()
|
||||
local matches = {}
|
||||
|
||||
for _, snippet in ipairs(result.items or {}) do
|
||||
-- Include if public or owned by user
|
||||
local accessible = snippet.isPublic or (userId and snippet.userId == userId)
|
||||
|
||||
if accessible then
|
||||
local searchable = (snippet.title or ''):lower() .. ' ' ..
|
||||
(snippet.description or ''):lower() .. ' ' ..
|
||||
(snippet.code or ''):lower()
|
||||
|
||||
if searchable:find(lowerQuery, 1, true) then
|
||||
table.insert(matches, snippet)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
---Update snippet
|
||||
---@param dbal table
|
||||
---@param snippetId string
|
||||
---@param updates table
|
||||
---@return table Updated snippet
|
||||
function M.updateSnippet(dbal, snippetId, updates)
|
||||
if updates.tags and type(updates.tags) == 'table' then
|
||||
updates.tags = json.encode(updates.tags)
|
||||
end
|
||||
|
||||
-- Increment version if code changed
|
||||
if updates.code then
|
||||
local snippet = M.getSnippet(dbal, snippetId)
|
||||
if snippet then
|
||||
updates.version = (snippet.version or 1) + 1
|
||||
end
|
||||
end
|
||||
|
||||
updates.updatedAt = os.time() * 1000
|
||||
return dbal:update('CodeSnippet', snippetId, updates)
|
||||
end
|
||||
|
||||
---Delete snippet
|
||||
---@param dbal table
|
||||
---@param snippetId string
|
||||
function M.deleteSnippet(dbal, snippetId)
|
||||
return dbal:delete('CodeSnippet', snippetId)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- EDITOR SESSION OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class SessionCreateParams
|
||||
---@field tenantId string
|
||||
---@field userId string
|
||||
---@field name string
|
||||
---@field files table[] Open files
|
||||
|
||||
---Create or update editor session
|
||||
---@param dbal table
|
||||
---@param params SessionCreateParams
|
||||
---@return table Session
|
||||
function M.saveSession(dbal, params)
|
||||
local existing = dbal:findFirst('EditorSession', {
|
||||
where = { tenantId = params.tenantId, userId = params.userId, name = params.name },
|
||||
})
|
||||
|
||||
if existing then
|
||||
return dbal:update('EditorSession', existing.id, {
|
||||
files = json.encode(params.files),
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return dbal:create('EditorSession', {
|
||||
tenantId = params.tenantId,
|
||||
userId = params.userId,
|
||||
name = params.name,
|
||||
files = json.encode(params.files),
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get session
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param name string
|
||||
---@return table|nil Session
|
||||
function M.getSession(dbal, tenantId, userId, name)
|
||||
local session = dbal:findFirst('EditorSession', {
|
||||
where = { tenantId = tenantId, userId = userId, name = name },
|
||||
})
|
||||
|
||||
if session and session.files then
|
||||
session.files = json.decode(session.files)
|
||||
end
|
||||
|
||||
return session
|
||||
end
|
||||
|
||||
---List user's sessions
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@return table[] Sessions
|
||||
function M.listSessions(dbal, tenantId, userId)
|
||||
local result = dbal:list('EditorSession', {
|
||||
where = { tenantId = tenantId, userId = userId },
|
||||
orderBy = { updatedAt = 'desc' },
|
||||
take = 50,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Delete session
|
||||
---@param dbal table
|
||||
---@param sessionId string
|
||||
function M.deleteSession(dbal, sessionId)
|
||||
return dbal:delete('EditorSession', sessionId)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- FILE REVISION OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Save file revision
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param filePath string
|
||||
---@param content string
|
||||
---@param userId string
|
||||
---@param message string|nil
|
||||
---@return table Revision
|
||||
function M.saveRevision(dbal, tenantId, filePath, content, userId, message)
|
||||
return dbal:create('FileRevision', {
|
||||
tenantId = tenantId,
|
||||
filePath = filePath,
|
||||
content = content,
|
||||
userId = userId,
|
||||
message = message,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get file revisions
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param filePath string
|
||||
---@param take number|nil
|
||||
---@return table[] Revisions
|
||||
function M.getRevisions(dbal, tenantId, filePath, take)
|
||||
local result = dbal:list('FileRevision', {
|
||||
where = { tenantId = tenantId, filePath = filePath },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 20,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Get specific revision
|
||||
---@param dbal table
|
||||
---@param revisionId string
|
||||
---@return table|nil Revision
|
||||
function M.getRevision(dbal, revisionId)
|
||||
return dbal:read('FileRevision', revisionId)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- LANGUAGE CONFIG OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Save language configuration
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param language string
|
||||
---@param config table
|
||||
function M.saveLanguageConfig(dbal, tenantId, language, config)
|
||||
local existing = dbal:findFirst('LanguageConfig', {
|
||||
where = { tenantId = tenantId, language = language },
|
||||
})
|
||||
|
||||
if existing then
|
||||
return dbal:update('LanguageConfig', existing.id, {
|
||||
config = json.encode(config),
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
return dbal:create('LanguageConfig', {
|
||||
tenantId = tenantId,
|
||||
language = language,
|
||||
config = json.encode(config),
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get language configuration
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param language string
|
||||
---@return table|nil Config
|
||||
function M.getLanguageConfig(dbal, tenantId, language)
|
||||
local record = dbal:findFirst('LanguageConfig', {
|
||||
where = { tenantId = tenantId, language = language },
|
||||
})
|
||||
|
||||
if record and record.config then
|
||||
return json.decode(record.config)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
---List supported languages
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@return table[] Language configs
|
||||
function M.listLanguages(dbal, tenantId)
|
||||
local result = dbal:list('LanguageConfig', {
|
||||
where = { tenantId = tenantId },
|
||||
orderBy = { language = 'asc' },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
return M
|
||||
335
packages/package_validator/seed/scripts/db/operations.lua
Normal file
335
packages/package_validator/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,335 @@
|
||||
-- package_validator/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for Package validation results
|
||||
-- @module package_validator.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- VALIDATION RUN OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ValidationRunParams
|
||||
---@field tenantId string
|
||||
---@field packageName string
|
||||
---@field packageVersion string|nil
|
||||
---@field status string (pending, running, completed, failed)
|
||||
---@field results table|nil Validation results
|
||||
|
||||
---Create validation run
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ValidationRunParams
|
||||
---@return table Created run
|
||||
function M.createRun(dbal, params)
|
||||
return dbal:create('ValidationRun', {
|
||||
tenantId = params.tenantId,
|
||||
packageName = params.packageName,
|
||||
packageVersion = params.packageVersion,
|
||||
status = params.status or 'pending',
|
||||
results = params.results and json.encode(params.results) or nil,
|
||||
startedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get validation run by ID
|
||||
---@param dbal table
|
||||
---@param runId string
|
||||
---@return table|nil Run
|
||||
function M.getRun(dbal, runId)
|
||||
local run = dbal:read('ValidationRun', runId)
|
||||
if run and run.results then
|
||||
run.results = json.decode(run.results)
|
||||
end
|
||||
return run
|
||||
end
|
||||
|
||||
---Update run status
|
||||
---@param dbal table
|
||||
---@param runId string
|
||||
---@param status string
|
||||
---@param results table|nil
|
||||
function M.updateRunStatus(dbal, runId, status, results)
|
||||
local updates = {
|
||||
status = status,
|
||||
}
|
||||
|
||||
if results then
|
||||
updates.results = json.encode(results)
|
||||
end
|
||||
|
||||
if status == 'completed' or status == 'failed' then
|
||||
updates.completedAt = os.time() * 1000
|
||||
end
|
||||
|
||||
return dbal:update('ValidationRun', runId, updates)
|
||||
end
|
||||
|
||||
---List runs for package
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param packageName string
|
||||
---@param take number|nil
|
||||
---@return table[] Runs
|
||||
function M.listRuns(dbal, tenantId, packageName, take)
|
||||
local result = dbal:list('ValidationRun', {
|
||||
where = { tenantId = tenantId, packageName = packageName },
|
||||
orderBy = { startedAt = 'desc' },
|
||||
take = take or 20,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Get latest run for package
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param packageName string
|
||||
---@return table|nil Latest run
|
||||
function M.getLatestRun(dbal, tenantId, packageName)
|
||||
local runs = M.listRuns(dbal, tenantId, packageName, 1)
|
||||
if #runs > 0 then
|
||||
local run = runs[1]
|
||||
if run.results then
|
||||
run.results = json.decode(run.results)
|
||||
end
|
||||
return run
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- VALIDATION ISSUE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ValidationIssue
|
||||
---@field runId string
|
||||
---@field severity string (error, warning, info)
|
||||
---@field code string Issue code
|
||||
---@field message string
|
||||
---@field file string|nil
|
||||
---@field line number|nil
|
||||
---@field suggestion string|nil
|
||||
|
||||
---Add validation issue
|
||||
---@param dbal table
|
||||
---@param issue ValidationIssue
|
||||
---@return table Created issue
|
||||
function M.addIssue(dbal, issue)
|
||||
return dbal:create('ValidationIssue', {
|
||||
runId = issue.runId,
|
||||
severity = issue.severity,
|
||||
code = issue.code,
|
||||
message = issue.message,
|
||||
file = issue.file,
|
||||
line = issue.line,
|
||||
suggestion = issue.suggestion,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Add multiple issues
|
||||
---@param dbal table
|
||||
---@param runId string
|
||||
---@param issues table[] Array of issues
|
||||
function M.addIssues(dbal, runId, issues)
|
||||
for _, issue in ipairs(issues) do
|
||||
issue.runId = runId
|
||||
M.addIssue(dbal, issue)
|
||||
end
|
||||
end
|
||||
|
||||
---Get issues for run
|
||||
---@param dbal table
|
||||
---@param runId string
|
||||
---@param severity string|nil Filter by severity
|
||||
---@return table[] Issues
|
||||
function M.getIssues(dbal, runId, severity)
|
||||
local where = { runId = runId }
|
||||
|
||||
local result = dbal:list('ValidationIssue', {
|
||||
where = where,
|
||||
orderBy = { severity = 'asc' },
|
||||
take = 500,
|
||||
})
|
||||
|
||||
local issues = result.items or {}
|
||||
|
||||
if severity then
|
||||
local filtered = {}
|
||||
for _, issue in ipairs(issues) do
|
||||
if issue.severity == severity then
|
||||
table.insert(filtered, issue)
|
||||
end
|
||||
end
|
||||
issues = filtered
|
||||
end
|
||||
|
||||
return issues
|
||||
end
|
||||
|
||||
---Count issues by severity
|
||||
---@param dbal table
|
||||
---@param runId string
|
||||
---@return table Counts by severity
|
||||
function M.countIssues(dbal, runId)
|
||||
local issues = M.getIssues(dbal, runId)
|
||||
|
||||
local counts = {
|
||||
error = 0,
|
||||
warning = 0,
|
||||
info = 0,
|
||||
total = #issues,
|
||||
}
|
||||
|
||||
for _, issue in ipairs(issues) do
|
||||
local sev = issue.severity
|
||||
if counts[sev] then
|
||||
counts[sev] = counts[sev] + 1
|
||||
end
|
||||
end
|
||||
|
||||
return counts
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- VALIDATION RULE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ValidationRuleParams
|
||||
---@field tenantId string
|
||||
---@field name string
|
||||
---@field code string Unique rule code
|
||||
---@field severity string
|
||||
---@field description string
|
||||
---@field check string Lua function body
|
||||
---@field enabled boolean|nil
|
||||
|
||||
---Create validation rule
|
||||
---@param dbal table
|
||||
---@param params ValidationRuleParams
|
||||
---@return table Created rule
|
||||
function M.createRule(dbal, params)
|
||||
return dbal:create('ValidationRule', {
|
||||
tenantId = params.tenantId,
|
||||
name = params.name,
|
||||
code = params.code,
|
||||
severity = params.severity,
|
||||
description = params.description,
|
||||
check = params.check,
|
||||
enabled = params.enabled ~= false,
|
||||
createdAt = os.time() * 1000,
|
||||
updatedAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get rule by code
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param code string
|
||||
---@return table|nil Rule
|
||||
function M.getRule(dbal, tenantId, code)
|
||||
return dbal:findFirst('ValidationRule', {
|
||||
where = { tenantId = tenantId, code = code },
|
||||
})
|
||||
end
|
||||
|
||||
---List enabled rules
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@return table[] Rules
|
||||
function M.listEnabledRules(dbal, tenantId)
|
||||
local result = dbal:list('ValidationRule', {
|
||||
where = { tenantId = tenantId, enabled = true },
|
||||
orderBy = { code = 'asc' },
|
||||
take = 100,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Update rule
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param code string
|
||||
---@param updates table
|
||||
function M.updateRule(dbal, tenantId, code, updates)
|
||||
local rule = M.getRule(dbal, tenantId, code)
|
||||
if rule then
|
||||
updates.updatedAt = os.time() * 1000
|
||||
return dbal:update('ValidationRule', rule.id, updates)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
---Toggle rule enabled status
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param code string
|
||||
---@param enabled boolean
|
||||
function M.setRuleEnabled(dbal, tenantId, code, enabled)
|
||||
return M.updateRule(dbal, tenantId, code, { enabled = enabled })
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- PACKAGE REGISTRY OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Get package validation summary
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param packageName string
|
||||
---@return table Summary
|
||||
function M.getPackageSummary(dbal, tenantId, packageName)
|
||||
local latestRun = M.getLatestRun(dbal, tenantId, packageName)
|
||||
|
||||
if not latestRun then
|
||||
return {
|
||||
packageName = packageName,
|
||||
status = 'never_validated',
|
||||
lastValidated = nil,
|
||||
issueCounts = nil,
|
||||
}
|
||||
end
|
||||
|
||||
local counts = M.countIssues(dbal, latestRun.id)
|
||||
|
||||
return {
|
||||
packageName = packageName,
|
||||
status = latestRun.status,
|
||||
lastValidated = latestRun.completedAt or latestRun.startedAt,
|
||||
issueCounts = counts,
|
||||
hasErrors = counts.error > 0,
|
||||
}
|
||||
end
|
||||
|
||||
---Get all packages validation status
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@return table[] Package summaries
|
||||
function M.getAllPackageStatus(dbal, tenantId)
|
||||
-- Get unique package names from runs
|
||||
local result = dbal:list('ValidationRun', {
|
||||
where = { tenantId = tenantId },
|
||||
orderBy = { packageName = 'asc' },
|
||||
take = 10000,
|
||||
})
|
||||
|
||||
local packageNames = {}
|
||||
local seen = {}
|
||||
|
||||
for _, run in ipairs(result.items or {}) do
|
||||
if not seen[run.packageName] then
|
||||
seen[run.packageName] = true
|
||||
table.insert(packageNames, run.packageName)
|
||||
end
|
||||
end
|
||||
|
||||
local summaries = {}
|
||||
for _, name in ipairs(packageNames) do
|
||||
table.insert(summaries, M.getPackageSummary(dbal, tenantId, name))
|
||||
end
|
||||
|
||||
return summaries
|
||||
end
|
||||
|
||||
return M
|
||||
312
packages/screenshot_analyzer/seed/scripts/db/operations.lua
Normal file
312
packages/screenshot_analyzer/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
-- screenshot_analyzer/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for Screenshot analysis
|
||||
-- @module screenshot_analyzer.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- SCREENSHOT OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ScreenshotParams
|
||||
---@field tenantId string
|
||||
---@field userId string
|
||||
---@field url string Image URL or base64
|
||||
---@field filename string|nil Original filename
|
||||
---@field metadata table|nil Additional metadata
|
||||
|
||||
---Save screenshot
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ScreenshotParams
|
||||
---@return table Created screenshot
|
||||
function M.saveScreenshot(dbal, params)
|
||||
return dbal:create('Screenshot', {
|
||||
tenantId = params.tenantId,
|
||||
userId = params.userId,
|
||||
url = params.url,
|
||||
filename = params.filename,
|
||||
metadata = params.metadata and json.encode(params.metadata) or nil,
|
||||
status = 'uploaded',
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get screenshot by ID
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@return table|nil Screenshot
|
||||
function M.getScreenshot(dbal, screenshotId)
|
||||
local ss = dbal:read('Screenshot', screenshotId)
|
||||
if ss and ss.metadata then
|
||||
ss.metadata = json.decode(ss.metadata)
|
||||
end
|
||||
return ss
|
||||
end
|
||||
|
||||
---List user's screenshots
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param take number|nil
|
||||
---@return table[] Screenshots
|
||||
function M.listUserScreenshots(dbal, tenantId, userId, take)
|
||||
local result = dbal:list('Screenshot', {
|
||||
where = { tenantId = tenantId, userId = userId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 50,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
---Update screenshot status
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@param status string
|
||||
function M.updateStatus(dbal, screenshotId, status)
|
||||
return dbal:update('Screenshot', screenshotId, { status = status })
|
||||
end
|
||||
|
||||
---Delete screenshot
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
function M.deleteScreenshot(dbal, screenshotId)
|
||||
-- Delete associated analyses first
|
||||
local analyses = M.listAnalyses(dbal, screenshotId)
|
||||
for _, analysis in ipairs(analyses) do
|
||||
dbal:delete('ScreenshotAnalysis', analysis.id)
|
||||
end
|
||||
|
||||
return dbal:delete('Screenshot', screenshotId)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- ANALYSIS OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class AnalysisParams
|
||||
---@field screenshotId string
|
||||
---@field analysisType string (component, color, layout, accessibility)
|
||||
---@field result table Analysis result data
|
||||
|
||||
---Create analysis record
|
||||
---@param dbal table
|
||||
---@param params AnalysisParams
|
||||
---@return table Created analysis
|
||||
function M.createAnalysis(dbal, params)
|
||||
return dbal:create('ScreenshotAnalysis', {
|
||||
screenshotId = params.screenshotId,
|
||||
analysisType = params.analysisType,
|
||||
result = json.encode(params.result),
|
||||
confidence = params.result.confidence,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get analysis by ID
|
||||
---@param dbal table
|
||||
---@param analysisId string
|
||||
---@return table|nil Analysis
|
||||
function M.getAnalysis(dbal, analysisId)
|
||||
local analysis = dbal:read('ScreenshotAnalysis', analysisId)
|
||||
if analysis and analysis.result then
|
||||
analysis.result = json.decode(analysis.result)
|
||||
end
|
||||
return analysis
|
||||
end
|
||||
|
||||
---List analyses for screenshot
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@return table[] Analyses
|
||||
function M.listAnalyses(dbal, screenshotId)
|
||||
local result = dbal:list('ScreenshotAnalysis', {
|
||||
where = { screenshotId = screenshotId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = 50,
|
||||
})
|
||||
|
||||
local analyses = result.items or {}
|
||||
for _, analysis in ipairs(analyses) do
|
||||
if analysis.result then
|
||||
analysis.result = json.decode(analysis.result)
|
||||
end
|
||||
end
|
||||
|
||||
return analyses
|
||||
end
|
||||
|
||||
---Get analysis by type
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@param analysisType string
|
||||
---@return table|nil Analysis
|
||||
function M.getAnalysisByType(dbal, screenshotId, analysisType)
|
||||
local analysis = dbal:findFirst('ScreenshotAnalysis', {
|
||||
where = { screenshotId = screenshotId, analysisType = analysisType },
|
||||
})
|
||||
|
||||
if analysis and analysis.result then
|
||||
analysis.result = json.decode(analysis.result)
|
||||
end
|
||||
|
||||
return analysis
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- DETECTED COMPONENT OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class DetectedComponentParams
|
||||
---@field analysisId string
|
||||
---@field componentType string
|
||||
---@field bounds table {x, y, width, height}
|
||||
---@field confidence number
|
||||
---@field properties table|nil
|
||||
|
||||
---Save detected component
|
||||
---@param dbal table
|
||||
---@param params DetectedComponentParams
|
||||
---@return table Created component
|
||||
function M.saveDetectedComponent(dbal, params)
|
||||
return dbal:create('DetectedComponent', {
|
||||
analysisId = params.analysisId,
|
||||
componentType = params.componentType,
|
||||
bounds = json.encode(params.bounds),
|
||||
confidence = params.confidence,
|
||||
properties = params.properties and json.encode(params.properties) or nil,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get detected components for analysis
|
||||
---@param dbal table
|
||||
---@param analysisId string
|
||||
---@return table[] Components
|
||||
function M.getDetectedComponents(dbal, analysisId)
|
||||
local result = dbal:list('DetectedComponent', {
|
||||
where = { analysisId = analysisId },
|
||||
orderBy = { confidence = 'desc' },
|
||||
take = 200,
|
||||
})
|
||||
|
||||
local components = result.items or {}
|
||||
for _, comp in ipairs(components) do
|
||||
if comp.bounds then
|
||||
comp.bounds = json.decode(comp.bounds)
|
||||
end
|
||||
if comp.properties then
|
||||
comp.properties = json.decode(comp.properties)
|
||||
end
|
||||
end
|
||||
|
||||
return components
|
||||
end
|
||||
|
||||
---Get components by type
|
||||
---@param dbal table
|
||||
---@param analysisId string
|
||||
---@param componentType string
|
||||
---@return table[] Components
|
||||
function M.getComponentsByType(dbal, analysisId, componentType)
|
||||
local all = M.getDetectedComponents(dbal, analysisId)
|
||||
local filtered = {}
|
||||
|
||||
for _, comp in ipairs(all) do
|
||||
if comp.componentType == componentType then
|
||||
table.insert(filtered, comp)
|
||||
end
|
||||
end
|
||||
|
||||
return filtered
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- COLOR PALETTE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ColorPaletteParams
|
||||
---@field analysisId string
|
||||
---@field colors table[] Array of {hex, rgb, usage, count}
|
||||
---@field dominantColor string|nil
|
||||
|
||||
---Save color palette
|
||||
---@param dbal table
|
||||
---@param params ColorPaletteParams
|
||||
---@return table Created palette
|
||||
function M.saveColorPalette(dbal, params)
|
||||
return dbal:create('ColorPalette', {
|
||||
analysisId = params.analysisId,
|
||||
colors = json.encode(params.colors),
|
||||
dominantColor = params.dominantColor,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get color palette for analysis
|
||||
---@param dbal table
|
||||
---@param analysisId string
|
||||
---@return table|nil Palette
|
||||
function M.getColorPalette(dbal, analysisId)
|
||||
local palette = dbal:findFirst('ColorPalette', {
|
||||
where = { analysisId = analysisId },
|
||||
})
|
||||
|
||||
if palette and palette.colors then
|
||||
palette.colors = json.decode(palette.colors)
|
||||
end
|
||||
|
||||
return palette
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- GENERATED CODE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class GeneratedCodeParams
|
||||
---@field screenshotId string
|
||||
---@field framework string (react, vue, html, qml)
|
||||
---@field code string
|
||||
---@field metadata table|nil
|
||||
|
||||
---Save generated code
|
||||
---@param dbal table
|
||||
---@param params GeneratedCodeParams
|
||||
---@return table Created code
|
||||
function M.saveGeneratedCode(dbal, params)
|
||||
return dbal:create('GeneratedCode', {
|
||||
screenshotId = params.screenshotId,
|
||||
framework = params.framework,
|
||||
code = params.code,
|
||||
metadata = params.metadata and json.encode(params.metadata) or nil,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get generated code for screenshot
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@param framework string
|
||||
---@return table|nil Generated code
|
||||
function M.getGeneratedCode(dbal, screenshotId, framework)
|
||||
return dbal:findFirst('GeneratedCode', {
|
||||
where = { screenshotId = screenshotId, framework = framework },
|
||||
})
|
||||
end
|
||||
|
||||
---List all generated code for screenshot
|
||||
---@param dbal table
|
||||
---@param screenshotId string
|
||||
---@return table[] Generated codes
|
||||
function M.listGeneratedCode(dbal, screenshotId)
|
||||
local result = dbal:list('GeneratedCode', {
|
||||
where = { screenshotId = screenshotId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = 20,
|
||||
})
|
||||
|
||||
return result.items or {}
|
||||
end
|
||||
|
||||
return M
|
||||
398
packages/social_hub/seed/scripts/db/operations.lua
Normal file
398
packages/social_hub/seed/scripts/db/operations.lua
Normal file
@@ -0,0 +1,398 @@
|
||||
-- social_hub/seed/scripts/db/operations.lua
|
||||
-- DBAL operations for Social features (profiles, connections, activity)
|
||||
-- @module social_hub.db.operations
|
||||
|
||||
local M = {}
|
||||
local json = require('json')
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- SOCIAL PROFILE OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ProfileParams
|
||||
---@field tenantId string
|
||||
---@field userId string
|
||||
---@field displayName string
|
||||
---@field bio string|nil
|
||||
---@field avatar string|nil
|
||||
---@field links table|nil Social links
|
||||
---@field settings table|nil Privacy settings
|
||||
|
||||
---Create or update social profile
|
||||
---@param dbal table DBAL client instance
|
||||
---@param params ProfileParams
|
||||
---@return table Profile
|
||||
function M.saveProfile(dbal, params)
|
||||
local existing = dbal:findFirst('SocialProfile', {
|
||||
where = { tenantId = params.tenantId, userId = params.userId },
|
||||
})
|
||||
|
||||
local data = {
|
||||
displayName = params.displayName,
|
||||
bio = params.bio,
|
||||
avatar = params.avatar,
|
||||
links = params.links and json.encode(params.links) or nil,
|
||||
settings = params.settings and json.encode(params.settings) or nil,
|
||||
updatedAt = os.time() * 1000,
|
||||
}
|
||||
|
||||
if existing then
|
||||
return dbal:update('SocialProfile', existing.id, data)
|
||||
end
|
||||
|
||||
data.tenantId = params.tenantId
|
||||
data.userId = params.userId
|
||||
data.createdAt = os.time() * 1000
|
||||
return dbal:create('SocialProfile', data)
|
||||
end
|
||||
|
||||
---Get profile by user ID
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@return table|nil Profile
|
||||
function M.getProfile(dbal, tenantId, userId)
|
||||
local profile = dbal:findFirst('SocialProfile', {
|
||||
where = { tenantId = tenantId, userId = userId },
|
||||
})
|
||||
|
||||
if profile then
|
||||
if profile.links then profile.links = json.decode(profile.links) end
|
||||
if profile.settings then profile.settings = json.decode(profile.settings) end
|
||||
end
|
||||
|
||||
return profile
|
||||
end
|
||||
|
||||
---Search profiles
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param query string
|
||||
---@param take number|nil
|
||||
---@return table[] Profiles
|
||||
function M.searchProfiles(dbal, tenantId, query, take)
|
||||
local result = dbal:list('SocialProfile', {
|
||||
where = { tenantId = tenantId },
|
||||
take = 1000,
|
||||
})
|
||||
|
||||
local lowerQuery = query:lower()
|
||||
local matches = {}
|
||||
|
||||
for _, profile in ipairs(result.items or {}) do
|
||||
local searchable = (profile.displayName or ''):lower() .. ' ' .. (profile.bio or ''):lower()
|
||||
if searchable:find(lowerQuery, 1, true) then
|
||||
table.insert(matches, profile)
|
||||
if #matches >= (take or 20) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- CONNECTION OPERATIONS (Following/Followers)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Follow a user
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param followerId string User doing the following
|
||||
---@param followingId string User being followed
|
||||
---@return table Connection
|
||||
function M.follow(dbal, tenantId, followerId, followingId)
|
||||
-- Check if already following
|
||||
local existing = dbal:findFirst('SocialConnection', {
|
||||
where = { tenantId = tenantId, followerId = followerId, followingId = followingId },
|
||||
})
|
||||
|
||||
if existing then
|
||||
return existing
|
||||
end
|
||||
|
||||
return dbal:create('SocialConnection', {
|
||||
tenantId = tenantId,
|
||||
followerId = followerId,
|
||||
followingId = followingId,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Unfollow a user
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param followerId string
|
||||
---@param followingId string
|
||||
function M.unfollow(dbal, tenantId, followerId, followingId)
|
||||
local connection = dbal:findFirst('SocialConnection', {
|
||||
where = { tenantId = tenantId, followerId = followerId, followingId = followingId },
|
||||
})
|
||||
|
||||
if connection then
|
||||
dbal:delete('SocialConnection', connection.id)
|
||||
end
|
||||
end
|
||||
|
||||
---Check if following
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param followerId string
|
||||
---@param followingId string
|
||||
---@return boolean
|
||||
function M.isFollowing(dbal, tenantId, followerId, followingId)
|
||||
local connection = dbal:findFirst('SocialConnection', {
|
||||
where = { tenantId = tenantId, followerId = followerId, followingId = followingId },
|
||||
})
|
||||
return connection ~= nil
|
||||
end
|
||||
|
||||
---Get followers
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param take number|nil
|
||||
---@return table[] Follower user IDs
|
||||
function M.getFollowers(dbal, tenantId, userId, take)
|
||||
local result = dbal:list('SocialConnection', {
|
||||
where = { tenantId = tenantId, followingId = userId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 50,
|
||||
})
|
||||
|
||||
local followers = {}
|
||||
for _, conn in ipairs(result.items or {}) do
|
||||
table.insert(followers, conn.followerId)
|
||||
end
|
||||
|
||||
return followers
|
||||
end
|
||||
|
||||
---Get following
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param take number|nil
|
||||
---@return table[] Following user IDs
|
||||
function M.getFollowing(dbal, tenantId, userId, take)
|
||||
local result = dbal:list('SocialConnection', {
|
||||
where = { tenantId = tenantId, followerId = userId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 50,
|
||||
})
|
||||
|
||||
local following = {}
|
||||
for _, conn in ipairs(result.items or {}) do
|
||||
table.insert(following, conn.followingId)
|
||||
end
|
||||
|
||||
return following
|
||||
end
|
||||
|
||||
---Get follower/following counts
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@return table Counts
|
||||
function M.getConnectionCounts(dbal, tenantId, userId)
|
||||
local followers = dbal:list('SocialConnection', {
|
||||
where = { tenantId = tenantId, followingId = userId },
|
||||
take = 100000,
|
||||
})
|
||||
|
||||
local following = dbal:list('SocialConnection', {
|
||||
where = { tenantId = tenantId, followerId = userId },
|
||||
take = 100000,
|
||||
})
|
||||
|
||||
return {
|
||||
followers = followers.total or #(followers.items or {}),
|
||||
following = following.total or #(following.items or {}),
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- ACTIVITY FEED OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---@class ActivityParams
|
||||
---@field tenantId string
|
||||
---@field userId string
|
||||
---@field type string (post, like, comment, follow, etc.)
|
||||
---@field content string|nil
|
||||
---@field targetId string|nil Reference to target object
|
||||
---@field targetType string|nil Type of target
|
||||
---@field metadata table|nil
|
||||
|
||||
---Create activity
|
||||
---@param dbal table
|
||||
---@param params ActivityParams
|
||||
---@return table Activity
|
||||
function M.createActivity(dbal, params)
|
||||
return dbal:create('SocialActivity', {
|
||||
tenantId = params.tenantId,
|
||||
userId = params.userId,
|
||||
type = params.type,
|
||||
content = params.content,
|
||||
targetId = params.targetId,
|
||||
targetType = params.targetType,
|
||||
metadata = params.metadata and json.encode(params.metadata) or nil,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Get user's activity feed
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param take number|nil
|
||||
---@param skip number|nil
|
||||
---@return table[] Activities
|
||||
function M.getUserActivity(dbal, tenantId, userId, take, skip)
|
||||
local result = dbal:list('SocialActivity', {
|
||||
where = { tenantId = tenantId, userId = userId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = take or 20,
|
||||
skip = skip or 0,
|
||||
})
|
||||
|
||||
local activities = result.items or {}
|
||||
for _, activity in ipairs(activities) do
|
||||
if activity.metadata then
|
||||
activity.metadata = json.decode(activity.metadata)
|
||||
end
|
||||
end
|
||||
|
||||
return activities
|
||||
end
|
||||
|
||||
---Get home feed (activity from followed users)
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param take number|nil
|
||||
---@param skip number|nil
|
||||
---@return table[] Activities
|
||||
function M.getHomeFeed(dbal, tenantId, userId, take, skip)
|
||||
-- Get list of users being followed
|
||||
local following = M.getFollowing(dbal, tenantId, userId, 1000)
|
||||
|
||||
-- Include own activity
|
||||
table.insert(following, userId)
|
||||
|
||||
-- Get all activities (would be better with IN query support)
|
||||
local result = dbal:list('SocialActivity', {
|
||||
where = { tenantId = tenantId },
|
||||
orderBy = { createdAt = 'desc' },
|
||||
take = 1000,
|
||||
})
|
||||
|
||||
-- Filter to followed users
|
||||
local followingSet = {}
|
||||
for _, id in ipairs(following) do
|
||||
followingSet[id] = true
|
||||
end
|
||||
|
||||
local feed = {}
|
||||
local skipped = 0
|
||||
|
||||
for _, activity in ipairs(result.items or {}) do
|
||||
if followingSet[activity.userId] then
|
||||
if skipped >= (skip or 0) then
|
||||
if activity.metadata then
|
||||
activity.metadata = json.decode(activity.metadata)
|
||||
end
|
||||
table.insert(feed, activity)
|
||||
if #feed >= (take or 20) then
|
||||
break
|
||||
end
|
||||
else
|
||||
skipped = skipped + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return feed
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- LIKES OPERATIONS
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
---Like something
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param targetId string
|
||||
---@param targetType string
|
||||
---@return table Like
|
||||
function M.like(dbal, tenantId, userId, targetId, targetType)
|
||||
local existing = dbal:findFirst('SocialLike', {
|
||||
where = { tenantId = tenantId, userId = userId, targetId = targetId },
|
||||
})
|
||||
|
||||
if existing then
|
||||
return existing
|
||||
end
|
||||
|
||||
-- Create activity
|
||||
M.createActivity(dbal, {
|
||||
tenantId = tenantId,
|
||||
userId = userId,
|
||||
type = 'like',
|
||||
targetId = targetId,
|
||||
targetType = targetType,
|
||||
})
|
||||
|
||||
return dbal:create('SocialLike', {
|
||||
tenantId = tenantId,
|
||||
userId = userId,
|
||||
targetId = targetId,
|
||||
targetType = targetType,
|
||||
createdAt = os.time() * 1000,
|
||||
})
|
||||
end
|
||||
|
||||
---Unlike something
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param targetId string
|
||||
function M.unlike(dbal, tenantId, userId, targetId)
|
||||
local like = dbal:findFirst('SocialLike', {
|
||||
where = { tenantId = tenantId, userId = userId, targetId = targetId },
|
||||
})
|
||||
|
||||
if like then
|
||||
dbal:delete('SocialLike', like.id)
|
||||
end
|
||||
end
|
||||
|
||||
---Check if liked
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param userId string
|
||||
---@param targetId string
|
||||
---@return boolean
|
||||
function M.hasLiked(dbal, tenantId, userId, targetId)
|
||||
local like = dbal:findFirst('SocialLike', {
|
||||
where = { tenantId = tenantId, userId = userId, targetId = targetId },
|
||||
})
|
||||
return like ~= nil
|
||||
end
|
||||
|
||||
---Get like count
|
||||
---@param dbal table
|
||||
---@param tenantId string
|
||||
---@param targetId string
|
||||
---@return number
|
||||
function M.getLikeCount(dbal, tenantId, targetId)
|
||||
local result = dbal:list('SocialLike', {
|
||||
where = { tenantId = tenantId, targetId = targetId },
|
||||
take = 100000,
|
||||
})
|
||||
return result.total or #(result.items or {})
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -54,6 +54,31 @@ export const CardActions: React.FC<LuaComponentProps> = ({ className = 'p-6 pt-0
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const CardDescription: React.FC<LuaComponentProps> = ({ className = 'text-sm text-muted-foreground', children }) => (
|
||||
<p className={className}>{children}</p>
|
||||
)
|
||||
|
||||
// ScrollArea - scrollable container
|
||||
export const ScrollArea: React.FC<LuaComponentProps & { maxHeight?: string | number }> = ({
|
||||
className = 'overflow-auto',
|
||||
maxHeight,
|
||||
children
|
||||
}) => (
|
||||
<div className={className} style={{ maxHeight: maxHeight || 'auto' }}>{children}</div>
|
||||
)
|
||||
|
||||
// ComponentRef - placeholder for dynamic component references
|
||||
export const ComponentRef: React.FC<LuaComponentProps & { ref?: string; component?: string }> = ({
|
||||
ref: refId,
|
||||
component,
|
||||
className = 'p-2 border border-dashed rounded bg-muted/30',
|
||||
children
|
||||
}) => (
|
||||
<div className={className}>
|
||||
{children || <span className="text-xs text-muted-foreground">Component: {component || refId || 'unknown'}</span>}
|
||||
</div>
|
||||
)
|
||||
|
||||
export const Paper: React.FC<LuaComponentProps> = ({ className = 'rounded border p-4 bg-canvas', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
@@ -520,9 +545,12 @@ export const componentRegistry: Record<string, AnyComponent> = {
|
||||
CardHeader,
|
||||
CardContent,
|
||||
CardActions,
|
||||
CardDescription,
|
||||
CardTitle: CardHeader,
|
||||
CardFooter: CardActions,
|
||||
Paper,
|
||||
ScrollArea,
|
||||
ComponentRef,
|
||||
|
||||
// Typography
|
||||
Typography,
|
||||
|
||||
Reference in New Issue
Block a user