|
@@ -271,16 +271,57 @@ async function currentUser(request, required = true) { const current = request.u
|
|
|
function legacyUser(current, withToken = false) { const json = safe(current); const value = { ...json, userId: number(current.get('legacyUserId') || current.get('userid') || current.get('num')), userName: String(current.get('username') || ''), honeyName: String(current.get('nickname') || current.get('nickName') || current.get('realName') || current.get('username') || ''), userFace: String(current.get('avatar') || ''), mobile: String(current.get('mobile') || current.get('phone') || ''), groupId: number(current.get('legacyGroupId')), groupName: String(current.get('roleName') || '') }; if (withToken) value.sessionToken = current.getSessionToken(); return value; }
|
|
function legacyUser(current, withToken = false) { const json = safe(current); const value = { ...json, userId: number(current.get('legacyUserId') || current.get('userid') || current.get('num')), userName: String(current.get('username') || ''), honeyName: String(current.get('nickname') || current.get('nickName') || current.get('realName') || current.get('username') || ''), userFace: String(current.get('avatar') || ''), mobile: String(current.get('mobile') || current.get('phone') || ''), groupId: number(current.get('legacyGroupId')), groupName: String(current.get('roleName') || '') }; if (withToken) value.sessionToken = current.getSessionToken(); return value; }
|
|
|
async function findByLegacyId(className, fields, legacyId, aliases) { const query = new Parse.Query(className); tenant(query, fields); const field = aliases.find((name) => fields[name]); if (!field) return null; query.equalTo(field, number(legacyId)); return query.first({ useMasterKey: true }); }
|
|
async function findByLegacyId(className, fields, legacyId, aliases) { const query = new Parse.Query(className); tenant(query, fields); const field = aliases.find((name) => fields[name]); if (!field) return null; query.equalTo(field, number(legacyId)); return query.first({ useMasterKey: true }); }
|
|
|
async function paged(className, input, configure) { const fields = await fieldsOf(className); const paging = pageInput(input); const query = new Parse.Query(className); tenant(query, fields); if (configure) configure(query, fields); const total = await query.count({ useMasterKey: true }); query.skip((paging.index - 1) * paging.size); query.limit(paging.size); query.descending(fields.updatedAt ? 'updatedAt' : 'createdAt'); const rows = (await query.find({ useMasterKey: true })).filter(isVisible); return { rows: rows.map(safe), page: { itemCount: total, pageCount: Math.ceil(total / paging.size), pageIndex: paging.index, pageSize: paging.size } }; }
|
|
async function paged(className, input, configure) { const fields = await fieldsOf(className); const paging = pageInput(input); const query = new Parse.Query(className); tenant(query, fields); if (configure) configure(query, fields); const total = await query.count({ useMasterKey: true }); query.skip((paging.index - 1) * paging.size); query.limit(paging.size); query.descending(fields.updatedAt ? 'updatedAt' : 'createdAt'); const rows = (await query.find({ useMasterKey: true })).filter(isVisible); return { rows: rows.map(safe), page: { itemCount: total, pageCount: Math.ceil(total / paging.size), pageIndex: paging.index, pageSize: paging.size } }; }
|
|
|
-async function contentPage(input) {
|
|
|
|
|
- const paging = pageInput(input); const values = [DEFAULT_COMPANY_ID]; const clauses = ['"company" = $1'];
|
|
|
|
|
- if (input.objectId) { values.push(String(input.objectId)); clauses.push('"objectId" = $' + values.length); }
|
|
|
|
|
- if (input.generalId) { values.push(String(input.generalId)); clauses.push('CAST("generalId" AS text) = $' + values.length); }
|
|
|
|
|
|
|
+const CONTENT_ADDONS = {
|
|
|
|
|
+ 52: { className:'VocabularyWord', fields:['id','lj','sy','yb','yp'] },
|
|
|
|
|
+ 53: { className:'PracticeRecord', fields:['id','kcid','scid','xxcs','yhid','jrscb'] },
|
|
|
|
|
+ 54: { className:'CourseAppointment', fields:['id','pl','bxrq','dslx','dszt','fxpl','jffs','jssj','kcid','kssj','plxm','scsj','sdsd','szmd','szyh','yysj','yykcid'] },
|
|
|
|
|
+ 56: { className:'DailyStudyRecord', fields:['id','pl','con','djq','ygg','dqrq','dsid','fxrl','xxqs','szmdid','userId','learned'] },
|
|
|
|
|
+ 58: { className:'CourseBinding', fields:['id','yxx','cksl','kcid','syjd','yhid'] },
|
|
|
|
|
+ 59: { className:'LessonRecord', fields:['id','pf','jffs','jsmz','kcid','kclx','kcmc','kzsj','pjnr','pldp','xymz','yyds','plpjsj','szmdid'] },
|
|
|
|
|
+ 60: { className:'MemoryPracticeRecord', fields:['id','fxzt','kcid','plid','wcsj','yhid','kywrq','kywsj','xxjlid','orderId'] },
|
|
|
|
|
+ 61: { className:'AssessmentProfile', fields:['id','df','askid','wrong','userId','answerid','dontKnow','prevScore','totalScore'] }
|
|
|
|
|
+};
|
|
|
|
|
+const NODE_MODELS = { 28:58, 29:54, 32:53, 291:56, 296:59, 327:52, 388:60, 389:61 };
|
|
|
|
|
+const PRIVATE_CONTENT_MODELS = new Set([53,54,56,58,59,60,61]);
|
|
|
|
|
+function contentModel(input, nodeIds) { const explicit = number(input.modelId || input.modelid || input.ModelID); return explicit || (nodeIds.length === 1 ? NODE_MODELS[number(nodeIds[0])] || 0 : 0); }
|
|
|
|
|
+function requestedContentModel(input) { const nodes = String(input.nodeid || input.nid || input.nodes || '').split(',').map(number).filter(Boolean); return contentModel(input, nodes); }
|
|
|
|
|
+function legacyFilterPairs(input) {
|
|
|
|
|
+ const source = [input.myfield, input.myfield2].filter(Boolean).join('|'); if (!source) return [];
|
|
|
|
|
+ return source.split('|').map((part) => { const match = String(part).trim().match(/^([A-Za-z][A-Za-z0-9_.]*)=(.*)$/); if (!match) fail(400, '内容过滤条件格式错误'); return { name: match[1].replace(/^B\./i,''), value: match[2] }; });
|
|
|
|
|
+}
|
|
|
|
|
+function addonField(config, requested) { return config && config.fields.find((field) => field.toLowerCase() === String(requested).toLowerCase()); }
|
|
|
|
|
+function contentQueryRequiresAuth(action, input) { return (action === 'content_list' || action === 'content_list_llk') && (PRIVATE_CONTENT_MODELS.has(requestedContentModel(input)) || legacyFilterPairs(input).length > 0); }
|
|
|
|
|
+async function authorizeContentAccess(current, input) {
|
|
|
|
|
+ if (!PRIVATE_CONTENT_MODELS.has(requestedContentModel(input))) return; const pairs = legacyFilterPairs(input); await authorizeOwnerPairs(current, pairs.map((pair) => ({ name: pair.name.toLowerCase(), value: number(pair.value) })).filter((pair) => pair.value));
|
|
|
|
|
+}
|
|
|
|
|
+function isAdminUser(current) { const roles = Array.isArray(current.get('roles')) ? current.get('roles').map(String) : []; return current.get('isAdmin') === true || current.get('role') === 'admin' || roles.includes('admin'); }
|
|
|
|
|
+async function authorizeOwnerPairs(current, pairs) {
|
|
|
|
|
+ if (isAdminUser(current)) return; const owners = pairs.filter((pair) => ['userid','yhid','xymz','jsmz','szyh'].includes(pair.name)); if (!owners.length) fail(403, '私有内容查询必须限定用户');
|
|
|
|
|
+ const ownId = number(current.get('legacyUserId') || current.get('userid') || current.get('num')); const subjects = owners.filter((pair) => ['userid','yhid','xymz'].includes(pair.name)); if (subjects.some((pair) => pair.value === ownId)) return;
|
|
|
|
|
+ const targets = subjects.length ? subjects : owners; const fields = await fieldsOf('_User'); for (const targetId of [...new Set(targets.map((pair) => pair.value))]) { if (targetId === ownId) continue; const target = await findByLegacyId('_User', fields, targetId, ['legacyUserId','userid','num']); const agent = target && target.get('agent'); if (!target || !agent || agent.id !== current.id) fail(403, '无权查看该学员的内容记录'); }
|
|
|
|
|
+}
|
|
|
|
|
+async function authorizeContentDetail(current, detail) { const pairs = ['userId','yhid','xymz','jsmz','szyh'].map((name) => ({ name: name.toLowerCase(), value: number(detail[name] ?? detail[name === 'userId' ? 'UserID' : name]) })).filter((pair) => pair.value); await authorizeOwnerPairs(current, pairs); }
|
|
|
|
|
+function contentOrder(input, config) {
|
|
|
|
|
+ const raw = String(input.orders || '').trim(); if (!raw) return 'c."updatedAt" DESC'; if (/^NEWID\(\)$/i.test(raw)) return 'RANDOM()';
|
|
|
|
|
+ const match = raw.match(/^([A-Za-z][A-Za-z0-9_.]*)\s*=\s*(ASC|DESC)$/i); if (!match) return 'c."updatedAt" DESC'; const requested = match[1].replace(/^B\./i,''); const direction = match[2].toUpperCase();
|
|
|
|
|
+ const addon = addonField(config, requested); if (addon) return 'a."' + addon + '" ' + direction; const base = { id:'itemId', generalid:'generalId', createtime:'createTime', updatedat:'updatedAt', title:'title' }[requested.toLowerCase()]; return base ? 'c."' + base + '" ' + direction : 'c."updatedAt" DESC';
|
|
|
|
|
+}
|
|
|
|
|
+async function contentPage(input, publicOnly = false) {
|
|
|
|
|
+ const paging = pageInput(input); const values = [DEFAULT_COMPANY_ID]; const clauses = ['c."company" = $1'];
|
|
|
|
|
+ if (input.objectId) { values.push(String(input.objectId)); clauses.push('c."objectId" = $' + values.length); }
|
|
|
|
|
+ if (input.generalId) { values.push(String(input.generalId)); clauses.push('CAST(c."generalId" AS text) = $' + values.length); }
|
|
|
const nodeIds = String(input.nodeid || input.nid || input.nodes || '').split(',').map((value) => String(number(value))).filter((value) => value !== '0');
|
|
const nodeIds = String(input.nodeid || input.nid || input.nodes || '').split(',').map((value) => String(number(value))).filter((value) => value !== '0');
|
|
|
- if (nodeIds.length) { values.push(nodeIds); clauses.push('CAST("nodeId" AS text) = ANY($' + values.length + '::text[])'); }
|
|
|
|
|
- if (input.modelid) { values.push(String(number(input.modelid))); clauses.push('CAST("modelId" AS text) = $' + values.length); }
|
|
|
|
|
- const where = clauses.join(' AND '); const countRow = await Psql.one('SELECT COUNT(*)::int AS total FROM "CommonModel" WHERE ' + where, values);
|
|
|
|
|
- const rowValues = values.concat([paging.size, (paging.index - 1) * paging.size]); const rows = await Psql.query('SELECT * FROM "CommonModel" WHERE ' + where + ' ORDER BY "updatedAt" DESC LIMIT $' + (values.length + 1) + ' OFFSET $' + (values.length + 2), rowValues);
|
|
|
|
|
- const total = number(countRow.total); return { rows: rows.filter(isVisible).map((row) => legacyAliases(row, 'CommonModel')), page: { itemCount: total, pageCount: Math.ceil(total / paging.size), pageIndex: paging.index, pageSize: paging.size } };
|
|
|
|
|
|
|
+ if (nodeIds.length) { values.push(nodeIds); clauses.push('CAST(c."nodeId" AS text) = ANY($' + values.length + '::text[])'); }
|
|
|
|
|
+ const modelId = contentModel(input, nodeIds); const config = CONTENT_ADDONS[modelId] || null; if (modelId) { values.push(String(modelId)); clauses.push('CAST(c."modelId" AS text) = $' + values.length); }
|
|
|
|
|
+ if (publicOnly && !modelId) { values.push([...PRIVATE_CONTENT_MODELS].map(String)); clauses.push('CAST(c."modelId" AS text) <> ALL($' + values.length + '::text[])'); }
|
|
|
|
|
+ const filters = legacyFilterPairs(input); if (filters.length && !config) fail(501, '该内容模型的 addon 联表尚未映射');
|
|
|
|
|
+ for (const filter of filters) { const field = addonField(config, filter.name); if (!field) fail(501, 'addon 字段尚未映射: ' + filter.name); values.push(String(filter.value)); clauses.push('CAST(a."' + field + '" AS text) = $' + values.length); }
|
|
|
|
|
+ if (input.skey) { values.push('%' + String(input.skey).replace(/[%_]/g, '') + '%'); clauses.push('c."title" ILIKE $' + values.length); }
|
|
|
|
|
+ const join = config ? ' LEFT JOIN "' + config.className + '" a ON a."company" = $1 AND CAST(a."id" AS text) = CAST(c."itemId" AS text)' : ''; const where = clauses.join(' AND ');
|
|
|
|
|
+ const countRow = await Psql.one('SELECT COUNT(*)::int AS total FROM "CommonModel" c' + join + ' WHERE ' + where, values); const rowValues = values.concat([paging.size, (paging.index - 1) * paging.size]);
|
|
|
|
|
+ const select = config ? 'c.*, row_to_json(a) AS "__addon"' : 'c.*'; const rows = await Psql.query('SELECT ' + select + ' FROM "CommonModel" c' + join + ' WHERE ' + where + ' ORDER BY ' + contentOrder(input, config) + ' LIMIT $' + (values.length + 1) + ' OFFSET $' + (values.length + 2), rowValues);
|
|
|
|
|
+ const normalized = rows.filter(isVisible).map((source) => { const addon = source.__addon || {}; const row = { ...source, ...addon }; delete row.__addon; if (source.objectId) row.objectId = source.objectId; return legacyAliases(row, 'CommonModel'); }); const total = number(countRow.total);
|
|
|
|
|
+ return { rows: normalized, page: { itemCount: total, pageCount: Math.ceil(total / paging.size), pageIndex: paging.index, pageSize: paging.size } };
|
|
|
}
|
|
}
|
|
|
async function sqlPage(className, input, filters = []) {
|
|
async function sqlPage(className, input, filters = []) {
|
|
|
if (!['App','Node','Product'].includes(className)) fail(400, '不允许查询该类'); const paging = pageInput(input); const values = [DEFAULT_COMPANY_ID]; const clauses = ['"company" = $1'];
|
|
if (!['App','Node','Product'].includes(className)) fail(400, '不允许查询该类'); const paging = pageInput(input); const values = [DEFAULT_COMPANY_ID]; const clauses = ['"company" = $1'];
|
|
@@ -304,13 +345,13 @@ async function handler(request, response) {
|
|
|
const created = new Parse.User(); created.setUsername(username); created.setPassword(password); created.set('company', companyPointer()); created.set('type','user'); created.set('isDisabled', false); await created.signUp(); return response.json(envelope(legacyUser(created, true), { State: 1 }));
|
|
const created = new Parse.User(); created.setUsername(username); created.setPassword(password); created.set('company', companyPointer()); created.set('type','user'); created.set('isDisabled', false); await created.signUp(); return response.json(envelope(legacyUser(created, true), { State: 1 }));
|
|
|
}
|
|
}
|
|
|
if (action === 'user_info_name') { const username = String(input.uname || input.name || '').trim(); if (!username) return response.status(400).json(reject('缺少用户名')); const rows = await Psql.query('SELECT "objectId" FROM "_User" WHERE "company" = $1 AND "username" = $2 LIMIT 1', [DEFAULT_COMPANY_ID, username]); const found = rows[0]; return found ? response.json(envelope({ objectId: found.objectId })) : response.status(404).json(reject('用户不存在')); }
|
|
if (action === 'user_info_name') { const username = String(input.uname || input.name || '').trim(); if (!username) return response.status(400).json(reject('缺少用户名')); const rows = await Psql.query('SELECT "objectId" FROM "_User" WHERE "company" = $1 AND "username" = $2 LIMIT 1', [DEFAULT_COMPANY_ID, username]); const found = rows[0]; return found ? response.json(envelope({ objectId: found.objectId })) : response.status(404).json(reject('用户不存在')); }
|
|
|
- const publicRead = PUBLIC_READ.has(action); const current = await currentUser(request, !publicRead);
|
|
|
|
|
|
|
+ const publicRead = PUBLIC_READ.has(action) && !contentQueryRequiresAuth(action, input); const current = await currentUser(request, !publicRead); if (contentQueryRequiresAuth(action, input) && current) await authorizeContentAccess(current, input);
|
|
|
if (action === 'user_get') { const requestedId = number(input.uid || current.id); let target = current; const ownId = number(current.get('legacyUserId') || current.get('userid') || current.get('num')); if (requestedId && requestedId !== ownId) { const fields = await fieldsOf('_User'); const found = await findByLegacyId('_User', fields, requestedId, ['legacyUserId','userid','num']); if (!found) return response.status(404).json(reject('用户不存在')); const isAdmin = current.get('isAdmin') === true; const isAgentChild = found.get('agent') && found.get('agent').id === current.id; if (!isAdmin && !isAgentChild) return response.status(403).json(reject('无权查看该用户')); target = found; } return response.json(envelope(legacyUser(target), { State: target.get('isDisabled') === true ? 0 : 1 })); }
|
|
if (action === 'user_get') { const requestedId = number(input.uid || current.id); let target = current; const ownId = number(current.get('legacyUserId') || current.get('userid') || current.get('num')); if (requestedId && requestedId !== ownId) { const fields = await fieldsOf('_User'); const found = await findByLegacyId('_User', fields, requestedId, ['legacyUserId','userid','num']); if (!found) return response.status(404).json(reject('用户不存在')); const isAdmin = current.get('isAdmin') === true; const isAgentChild = found.get('agent') && found.get('agent').id === current.id; if (!isAdmin && !isAgentChild) return response.status(403).json(reject('无权查看该用户')); target = found; } return response.json(envelope(legacyUser(target), { State: target.get('isDisabled') === true ? 0 : 1 })); }
|
|
|
if (action === 'user_list' || action === 'e_user_list') { if (action === 'user_list' && current.get('isAdmin') !== true) return response.status(403).json(reject('仅管理员可查询全量用户')); const result = await paged('_User', input, (query, fields) => { const uid = number(current.get('legacyUserId') || current.get('userid')); if (action === 'e_user_list' && fields.agent) query.equalTo('agent', current); else if (fields.legacyUserId && uid) query.notEqualTo('legacyUserId', uid); }); return response.json(envelope(result.rows.map((row) => ({ ...row, userId: number(row.legacyUserId || row.userid || row.num), userName: row.username, honeyName: row.nickname || row.realName || row.username })), undefined, result.page)); }
|
|
if (action === 'user_list' || action === 'e_user_list') { if (action === 'user_list' && current.get('isAdmin') !== true) return response.status(403).json(reject('仅管理员可查询全量用户')); const result = await paged('_User', input, (query, fields) => { const uid = number(current.get('legacyUserId') || current.get('userid')); if (action === 'e_user_list' && fields.agent) query.equalTo('agent', current); else if (fields.legacyUserId && uid) query.notEqualTo('legacyUserId', uid); }); return response.json(envelope(result.rows.map((row) => ({ ...row, userId: number(row.legacyUserId || row.userid || row.num), userName: row.username, honeyName: row.nickname || row.realName || row.username })), undefined, result.page)); }
|
|
|
if (action === 'user_update' || action === 'user_update_pwd' || action === 'user_update_pwdall') { if (action !== 'user_update') { const password = String(input.passwd || input.password || input.pwd || ''); if (password.length < 8) return response.status(400).json(reject('新密码至少 8 位')); current.setPassword(password); current.set('passwordResetRequired', false); } else { const allowed = { honeyName:'nickname', nickname:'nickname', mobile:'mobile', userFace:'avatar', avatar:'avatar', realName:'realName', gender:'gender', school:'school' }; for (const [source,target] of Object.entries(allowed)) if (input[source] !== undefined) current.set(target, input[source]); } await current.save(null, { useMasterKey: true }); return response.json(envelope(legacyUser(current, action !== 'user_update'))); }
|
|
if (action === 'user_update' || action === 'user_update_pwd' || action === 'user_update_pwdall') { if (action !== 'user_update') { const password = String(input.passwd || input.password || input.pwd || ''); if (password.length < 8) return response.status(400).json(reject('新密码至少 8 位')); current.setPassword(password); current.set('passwordResetRequired', false); } else { const allowed = { honeyName:'nickname', nickname:'nickname', mobile:'mobile', userFace:'avatar', avatar:'avatar', realName:'realName', gender:'gender', school:'school' }; for (const [source,target] of Object.entries(allowed)) if (input[source] !== undefined) current.set(target, input[source]); } await current.save(null, { useMasterKey: true }); return response.json(envelope(legacyUser(current, action !== 'user_update'))); }
|
|
|
if (action === 'app_update') { const filters = input.platform ? [{ field: 'platform', value: input.platform }] : []; const result = await sqlPage('App', { page: 1, pageSize: 1 }, filters); return response.json(envelope(result.rows[0] || null)); }
|
|
if (action === 'app_update') { const filters = input.platform ? [{ field: 'platform', value: input.platform }] : []; const result = await sqlPage('App', { page: 1, pageSize: 1 }, filters); return response.json(envelope(result.rows[0] || null)); }
|
|
|
- if (action === 'content_list' || action === 'content_list_llk') { const result = await contentPage(input); return response.json(envelope(result.rows, undefined, result.page)); }
|
|
|
|
|
- if (action === 'content_get') { const id = String(input.id || input.gid || input.generalId || ''); if (!id) return response.status(400).json(reject('缺少内容 ID')); const result = await contentPage({ page: 1, pageSize: 1, ...(/^[A-Za-z0-9_-]{10,40}$/.test(id) ? { objectId: id } : { generalId: id }) }); return result.rows[0] ? response.json(envelope(result.rows[0])) : response.status(404).json(reject('内容不存在')); }
|
|
|
|
|
|
|
+ if (action === 'content_list' || action === 'content_list_llk') { const result = await contentPage(input, !current); return response.json(envelope(result.rows, undefined, result.page)); }
|
|
|
|
|
+ if (action === 'content_get') { const id = String(input.id || input.gid || input.generalId || ''); if (!id) return response.status(400).json(reject('缺少内容 ID')); const identity = /^[A-Za-z0-9_-]{10,40}$/.test(id) ? { objectId: id } : { generalId: id }; const base = await contentPage({ page: 1, pageSize: 1, ...identity }); let detail = base.rows[0]; if (!detail) return response.status(404).json(reject('内容不存在')); const detailModel = number(detail.modelId || detail.ModelID); if (CONTENT_ADDONS[detailModel]) detail = (await contentPage({ page: 1, pageSize: 1, modelId: detailModel, ...identity })).rows[0] || detail; if (PRIVATE_CONTENT_MODELS.has(detailModel)) { if (!current) return response.status(401).json(reject('该内容详情需要登录')); await authorizeContentDetail(current, detail); } return response.json(envelope(detail)); }
|
|
|
if (action === 'content_uphis') { const resolved = await resolveContent(input, true); if (!resolved.object) return response.status(404).json(reject('内容不存在')); resolved.object.increment('hits', Math.max(1, number(input.num, 1))); await resolved.object.save(null, { useMasterKey: true }); return response.json(envelope({ hits: resolved.object.get('hits') })); }
|
|
if (action === 'content_uphis') { const resolved = await resolveContent(input, true); if (!resolved.object) return response.status(404).json(reject('内容不存在')); resolved.object.increment('hits', Math.max(1, number(input.num, 1))); await resolved.object.save(null, { useMasterKey: true }); return response.json(envelope({ hits: resolved.object.get('hits') })); }
|
|
|
if (action === 'content_add' || action === 'content_update') { if (!current) fail(401,'需要登录'); const resolved = action === 'content_update' ? await resolveContent(input, true) : { object: new Parse.Object('CommonModel'), fields: await fieldsOf('CommonModel') }; const object = resolved.object; if (!object) return response.status(404).json(reject('内容不存在')); const allowed = ['title','subtitle','nodeId','modelId','status','topImg','tagKey','template']; for (const name of allowed) if (input[name] !== undefined && resolved.fields[name]) object.set(name, ['nodeId','modelId','status'].includes(name) ? number(input[name]) : input[name]); object.set('company', companyPointer()); object.set('inputer', String(current.get('username') || '')); await object.save(null, { useMasterKey: true }); return response.json(envelope(safe(object))); }
|
|
if (action === 'content_add' || action === 'content_update') { if (!current) fail(401,'需要登录'); const resolved = action === 'content_update' ? await resolveContent(input, true) : { object: new Parse.Object('CommonModel'), fields: await fieldsOf('CommonModel') }; const object = resolved.object; if (!object) return response.status(404).json(reject('内容不存在')); const allowed = ['title','subtitle','nodeId','modelId','status','topImg','tagKey','template']; for (const name of allowed) if (input[name] !== undefined && resolved.fields[name]) object.set(name, ['nodeId','modelId','status'].includes(name) ? number(input[name]) : input[name]); object.set('company', companyPointer()); object.set('inputer', String(current.get('username') || '')); await object.save(null, { useMasterKey: true }); return response.json(envelope(safe(object))); }
|
|
|
if (action === 'node_list') { const filters = input.pid !== undefined ? [{ field: 'parentId', value: number(input.pid) }] : []; const result = await sqlPage('Node', input, filters); return response.json(envelope(result.rows, undefined, result.page)); }
|
|
if (action === 'node_list') { const filters = input.pid !== undefined ? [{ field: 'parentId', value: number(input.pid) }] : []; const result = await sqlPage('Node', input, filters); return response.json(envelope(result.rows, undefined, result.page)); }
|
|
@@ -376,7 +417,7 @@ async function upsert(definition) {
|
|
|
respType: 'json',
|
|
respType: 'json',
|
|
|
respJson: { success: true, data: {} },
|
|
respJson: { success: true, data: {} },
|
|
|
enabled: true,
|
|
enabled: true,
|
|
|
- version: '1.0.9',
|
|
|
|
|
|
|
+ version: '1.1.2',
|
|
|
};
|
|
};
|
|
|
const objectId = existing.results?.[0]?.objectId;
|
|
const objectId = existing.results?.[0]?.objectId;
|
|
|
if (objectId) {
|
|
if (objectId) {
|