| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /**
- * 云函数:remixManager(视频重塑记录)
- * 替代:GET/POST/DELETE /api/remixes[/:videoId[/:remixId]]
- * 支持 action:
- * listAll
- * listByVideo
- * upsert
- * delete
- */
- const { requireSession, assertRequestedUserMatchesSession } = require('./_session');
- async function handler(request, response) {
- try {
- await ensureTable();
- const action = pickParam(request, 'action') || 'listAll';
- const session = await requireSession(request, Psql);
- assertRequestedUserMatchesSession(request, session);
- const userId = session.userId;
- if (action === 'listAll') return listAll(response, userId);
- if (action === 'listByVideo') return listByVideo(request, response, userId);
- if (action === 'upsert') return upsertRemix(request, response, userId);
- if (action === 'delete') return deleteRemix(request, response, userId);
- return response.json({ code: 400, success: false, error: `未知 action: ${action}` });
- } catch (error) {
- console.error('remixManager failed:', error && error.message);
- return response.json({ code: error.status || 500, success: false, error: error.message });
- }
- }
- async function ensureTable() {
- await Psql.query(`
- CREATE TABLE IF NOT EXISTS "Remix" (
- "objectId" VARCHAR(50) PRIMARY KEY,
- "videoId" VARCHAR(255) NOT NULL,
- "remixId" VARCHAR(255) NOT NULL,
- "data" JSONB NOT NULL DEFAULT '{}',
- "userId" VARCHAR(255) DEFAULT '',
- "createdAt" TIMESTAMPTZ DEFAULT NOW(),
- "updatedAt" TIMESTAMPTZ DEFAULT NOW()
- )
- `);
- await Psql.query(`DROP INDEX IF EXISTS idx_remix_pair`);
- await Psql.query(`CREATE UNIQUE INDEX IF NOT EXISTS idx_remix_user_pair ON "Remix" ("userId", "videoId", "remixId")`);
- await Psql.query(`CREATE INDEX IF NOT EXISTS idx_remix_video ON "Remix" ("videoId")`);
- await Psql.query(`CREATE INDEX IF NOT EXISTS idx_remix_user ON "Remix" ("userId")`);
- }
- async function listAll(response, userId) {
- const rows = await Psql.query(
- `SELECT * FROM "Remix" WHERE "userId" = $1 ORDER BY "createdAt" DESC LIMIT 5000`,
- [userId]
- );
- const grouped = {};
- for (const row of rows) {
- if (!grouped[row.videoId]) grouped[row.videoId] = [];
- grouped[row.videoId].push(rowToObj(row));
- }
- return response.json({ code: 200, success: true, data: grouped });
- }
- async function listByVideo(request, response, userId) {
- const videoId = pickParam(request, 'videoId');
- if (!videoId) return response.json({ code: 400, success: false, error: '缺少 videoId' });
- const rows = await Psql.query(
- `SELECT * FROM "Remix" WHERE "videoId" = $1 AND "userId" = $2 ORDER BY "createdAt" DESC`,
- [videoId, userId]
- );
- return response.json({ code: 200, success: true, data: rows.map(rowToObj) });
- }
- async function upsertRemix(request, response, userId) {
- const videoId = pickParam(request, 'videoId');
- const body = pickParam(request, 'remix', 'data') || request.body || {};
- const remixId = body.remixId || pickParam(request, 'remixId');
- if (!videoId || !remixId) {
- return response.json({ code: 400, success: false, error: '缺少 videoId 或 remixId' });
- }
- const now = new Date().toISOString();
- const existing = await Psql.query(
- `SELECT * FROM "Remix" WHERE "videoId"=$1 AND "remixId"=$2 AND "userId"=$3 LIMIT 1`,
- [videoId, remixId, userId]
- );
- const previous = existing.length ? rowToObj(existing[0]) : {};
- const merged = {
- ...previous,
- ...body,
- remixId,
- videoId,
- userId,
- created_at: previous.created_at || body.created_at || now,
- updated_at: now,
- };
- await Psql.query(
- `INSERT INTO "Remix" ("objectId","videoId","remixId","data","userId")
- VALUES ($1,$2,$3,$4,$5)
- ON CONFLICT ("userId","videoId","remixId") DO UPDATE SET "data"=$4, "updatedAt"=NOW()`,
- [existing[0]?.objectId || generateId(), videoId, remixId, JSON.stringify(merged), userId]
- );
- return response.json({ code: 200, success: true, data: merged });
- }
- async function deleteRemix(request, response, userId) {
- const videoId = pickParam(request, 'videoId');
- const remixId = pickParam(request, 'remixId');
- if (!videoId || !remixId) {
- return response.json({ code: 400, success: false, error: '缺少 videoId 或 remixId' });
- }
- const result = await Psql.query(
- `DELETE FROM "Remix" WHERE "videoId"=$1 AND "remixId"=$2 AND "userId"=$3 RETURNING "objectId"`,
- [videoId, remixId, userId]
- );
- return response.json({ code: 200, success: true, data: { videoId, remixId, deleted: result.length > 0 } });
- }
- function rowToObj(row) {
- const data = typeof row.data === 'string' ? JSON.parse(row.data) : (row.data || {});
- return { ...data, objectId: row.objectId, createdAt: row.createdAt, updatedAt: row.updatedAt };
- }
- function pickParam(request, ...names) {
- const sources = [request.params, request.body, request.query, request];
- for (const src of sources) {
- if (!src || typeof src !== 'object') continue;
- for (const name of names) {
- const value = src[name];
- if (value !== undefined && value !== null && value !== '') return value;
- }
- }
- return null;
- }
- function generateId() {
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let value = '';
- for (let i = 0; i < 10; i += 1) value += chars.charAt(Math.floor(Math.random() * chars.length));
- return value;
- }
|