@opengis/cms 0.0.54 → 0.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +57 -24
  2. package/dist/{ArticlesPage-Cuit_90w.js → ArticlesPage-BcR1hbds.js} +3 -3
  3. package/dist/{BuilderPage-B79YHrmr.js → BuilderPage-CK_osM89.js} +51 -51
  4. package/dist/{CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-B6irHMzL.js → CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-CnOe9ORD.js} +19 -19
  5. package/dist/{EditCollectionPage-CAVLcvLg.js → EditCollectionPage-Cw3GQYRe.js} +2 -2
  6. package/dist/{MenuAddPage-CmU4kAUM.js → MenuAddPage-Bf48Z-ah.js} +1 -1
  7. package/dist/{MenuItemPage-UV8JlJvT.js → MenuItemPage-CXn5HC8j.js} +113 -112
  8. package/dist/{MenuPage-c4TPJgIN.js → MenuPage-tJZtK46W.js} +1 -1
  9. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-B1DrxmQX.js +84 -0
  10. package/dist/{UniversalTable.vue_vue_type_script_setup_true_lang-DR4PQwqR.js → UniversalTable.vue_vue_type_script_setup_true_lang-CJGTsd1V.js} +80 -80
  11. package/dist/{UniversalTablePagination.vue_vue_type_script_setup_true_lang-C8P9DCeX.js → UniversalTablePagination.vue_vue_type_script_setup_true_lang-GYZd_gkA.js} +46 -46
  12. package/dist/{contentForm-BQdeYVFh.js → contentForm-B6gHgGkz.js} +1 -1
  13. package/dist/index.js +5 -5
  14. package/dist/style.css +1 -1
  15. package/package.json +68 -68
  16. package/server/functions/getContent.js +3 -3
  17. package/server/functions/getSearchData.js +1 -1
  18. package/server/migrations/site.sql +2 -2
  19. package/server/routes/cms/controllers/getContent.js +6 -4
  20. package/server/routes/cms/controllers/getPermissions.js +15 -15
  21. package/server/routes/cms/controllers/setPermissions.js +49 -49
  22. package/server/routes/cms/controllers/updateContent.js +27 -1
  23. package/server/routes/cms/functions/getSettings.js +1 -1
  24. package/server/routes/cms/utils/getSingle.js +6 -10
  25. package/server/routes/contentType/controllers/editContentType.js +29 -9
  26. package/server/routes/contentType/controllers/getContentType.js +13 -0
  27. package/server/routes/contentType/utils/updateContents.js +16 -0
  28. package/server/routes/menu/controllers/getMenu.js +2 -2
  29. package/server/routes/menu/functions/getMenu.js +3 -3
  30. package/server/templates/select/core.user_mentioned.sql +1 -1
  31. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-C8cip9Ci.js +0 -84
package/package.json CHANGED
@@ -1,68 +1,68 @@
1
- {
2
- "name": "@opengis/cms",
3
- "version": "0.0.54",
4
- "description": "cms",
5
- "type": "module",
6
- "author": "Softpro",
7
- "main": "./dist/index.js",
8
- "license": "EULA",
9
- "files": [
10
- "module",
11
- "locales",
12
- "dist",
13
- "server",
14
- "plugin.js",
15
- "utils.js",
16
- "utils.d.ts",
17
- "input-types.json"
18
- ],
19
- "scripts": {
20
- "patch": "npm version patch && git push && npm publish",
21
- "test": "node --test test/**/*.test.js",
22
- "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
23
- "dev": "NODE_ENV=dev bun --env-file=.env.ip server ",
24
- "admin": "vite admin",
25
- "build": "vite build && vite build admin",
26
- "build:lib": "vite build",
27
- "proxy": "vite dev admin",
28
- "start": "bun --env-file=.env.ip server",
29
- "prod": "NODE_ENV=production bun --env-file=.env.ip server ",
30
- "ip": "bun --env-file=.env.ip server",
31
- "demo": "node --env-file=.env.demo --env-file=.env server",
32
- "i18n:sync": "node i18n-sync.cjs",
33
- "prepublishOnly": "bun build:lib",
34
- "softpro": "bun --env-file=.env.softpro server",
35
- "softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
36
- },
37
- "dependencies": {},
38
- "resolutions": {
39
- "rollup": "4.30.0"
40
- },
41
- "devDependencies": {
42
- "@fastify/compress": "^8.1.0",
43
- "@opengis/core": "^0.0.30",
44
- "@opengis/fastify-table": "^2.0.143",
45
- "@opengis/filter": "^0.1.31",
46
- "@opengis/form": "^0.0.109",
47
- "@opengis/richtext": "0.0.45",
48
- "@vueuse/head": "2.0.0",
49
- "js-yaml": "^4.1.0",
50
- "lucide-vue-next": "0.344.0",
51
- "vite": "5.1.4",
52
- "vue": "^3.5.17",
53
- "vue-i18n": "11.1.5",
54
- "vue-router": "4.4.3",
55
- "vuedraggable": "4.1.0",
56
- "@tailwindcss/typography": "0.5.10",
57
- "@tsconfig/node22": "^22.0.2",
58
- "@vitejs/plugin-vue": "5.0.4",
59
- "autoprefixer": "10.4.18",
60
- "eslint": "8.49.0",
61
- "postcss": "8.4.35",
62
- "sass": "^1.92.1",
63
- "tailwindcss": "3.4.1",
64
- "typescript": "~5.8.0",
65
- "vitest": "3.2.4",
66
- "vue-tsc": "^2.2.10"
67
- }
68
- }
1
+ {
2
+ "name": "@opengis/cms",
3
+ "version": "0.0.56",
4
+ "description": "cms",
5
+ "type": "module",
6
+ "author": "Softpro",
7
+ "main": "./dist/index.js",
8
+ "license": "EULA",
9
+ "files": [
10
+ "module",
11
+ "locales",
12
+ "dist",
13
+ "server",
14
+ "plugin.js",
15
+ "utils.js",
16
+ "utils.d.ts",
17
+ "input-types.json"
18
+ ],
19
+ "scripts": {
20
+ "patch": "npm version patch && git push && npm publish",
21
+ "test": "node --test test/**/*.test.js",
22
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
23
+ "dev": "NODE_ENV=dev bun --env-file=.env.ip server ",
24
+ "admin": "vite admin",
25
+ "build": "vite build && vite build admin",
26
+ "build:lib": "vite build",
27
+ "proxy": "vite dev admin",
28
+ "start": "bun --env-file=.env.ip server",
29
+ "prod": "NODE_ENV=production bun --env-file=.env.ip server ",
30
+ "ip": "bun --env-file=.env.ip server",
31
+ "demo": "node --env-file=.env.demo --env-file=.env server",
32
+ "i18n:sync": "node i18n-sync.cjs",
33
+ "prepublishOnly": "bun build:lib",
34
+ "softpro": "bun --env-file=.env.softpro server",
35
+ "softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
36
+ },
37
+ "dependencies": {},
38
+ "resolutions": {
39
+ "rollup": "4.30.0"
40
+ },
41
+ "devDependencies": {
42
+ "@fastify/compress": "^8.1.0",
43
+ "@opengis/core": "^0.0.30",
44
+ "@opengis/fastify-table": "^2.0.143",
45
+ "@opengis/filter": "^0.1.31",
46
+ "@opengis/form": "^0.0.109",
47
+ "@opengis/richtext": "0.0.45",
48
+ "@vueuse/head": "2.0.0",
49
+ "js-yaml": "^4.1.0",
50
+ "lucide-vue-next": "0.344.0",
51
+ "vite": "5.1.4",
52
+ "vue": "^3.5.17",
53
+ "vue-i18n": "11.1.5",
54
+ "vue-router": "4.4.3",
55
+ "vuedraggable": "4.1.0",
56
+ "@tailwindcss/typography": "0.5.10",
57
+ "@tsconfig/node22": "^22.0.2",
58
+ "@vitejs/plugin-vue": "5.0.4",
59
+ "autoprefixer": "10.4.18",
60
+ "eslint": "8.49.0",
61
+ "postcss": "8.4.35",
62
+ "sass": "^1.92.1",
63
+ "tailwindcss": "3.4.1",
64
+ "typescript": "~5.8.0",
65
+ "vitest": "3.2.4",
66
+ "vue-tsc": "^2.2.10"
67
+ }
68
+ }
@@ -22,9 +22,9 @@ export default async function getContentBySlug({ slug, filter, tags, state, loca
22
22
  }
23
23
 
24
24
  // check if any crud operations performed, if not - return cached response
25
- const crudInc = await rclient.get(`pg:${table}:crud`) || 0;
25
+ const crudInc = await rclient.get(`pg:${config.pg?.database}:${table}:crud`) || 0;
26
26
 
27
- const cacheKey = createHash('md5').update([config.pg?.database, 'cms:content', slug, crudInc, filter, tags, state, locale, contextQuery, collection, fields, limit, page, fields && typeof fields !== 'string' ? JSON.stringify(fields) : fields].join(':')).digest('hex');
27
+ const cacheKey = createHash('md5').update([config.pg?.database, 'cms:content', slug, crudInc, filter, tags, state, locale, contextQuery, collection, fields, limit, page, order, desc, fields && typeof fields !== 'string' ? JSON.stringify(fields) : fields].join(':')).digest('hex');
28
28
  const cacheData = ttl === 0 ? null : JSON.parse(await rclient.get(cacheKey));
29
29
 
30
30
  // return from cache
@@ -33,7 +33,7 @@ export default async function getContentBySlug({ slug, filter, tags, state, loca
33
33
  }
34
34
 
35
35
  const req = { pg: pgClients.client, params: { type: collection, id: slug }, query: { filter, tags, state, contextQuery, locale, fields, limit, page, order, desc } };
36
-
36
+
37
37
  const mockReply = createMockReply();
38
38
  const result = await getContent(req, mockReply, true);
39
39
 
@@ -10,7 +10,7 @@ const rclient = getRedis();
10
10
 
11
11
  export default async function getSearchData({ page = 1, limit = 12, ttl = 3600, search, locale, tags, filter, contentType, asc } = {}) {
12
12
  // check if any crud operations performed, if not - return cached response
13
- const crudInc = await rclient.get(`pg:site.contents:crud`) || 0;
13
+ const crudInc = await rclient.get(`pg:${config.pg?.database}:site.contents:crud`) || 0;
14
14
 
15
15
  const cacheKey = createHash('md5').update([config.pg?.database, 'cms:search', crudInc, page, limit, search, locale, tags, filter, contentType, asc].join(':')).digest('hex');
16
16
  const cacheData = ttl === 0 ? null : JSON.parse(await rclient.get(cacheKey));
@@ -370,8 +370,8 @@ CREATE TABLE if not exists site.contents (
370
370
  FOREIGN KEY (updated_by) REFERENCES admin.users(uid)
371
371
  );
372
372
 
373
- alter table site.contents add column if not exists space_id text;
374
- alter table site.contents add column if not exists content_type_id text;
373
+ alter table site.contents add column if not exists space_id text;
374
+ alter table site.contents add column if not exists content_type_id text;
375
375
  ALTER TABLE site.contents add COLUMN if not exists created_at TIMESTAMP DEFAULT NOW();
376
376
  ALTER TABLE site.contents add COLUMN if not exists updated_at TIMESTAMP DEFAULT NOW();
377
377
  ALTER TABLE site.contents add COLUMN if not exists created_by text REFERENCES admin.users(uid);
@@ -35,7 +35,9 @@ addHook('preFilter', async ({ pg = pgClients.client, table }) => {
35
35
 
36
36
  const defaultFields = ['title', 'slug', 'status', 'created_at', 'updated_at', 'main_image', 'published_at'];
37
37
 
38
- export default async function getContent(req, reply, called = false) {
38
+ export default async function getContent(req, reply, opt) {
39
+ const called = !!opt;
40
+ const { showDrafts: showDrafts1 } = opt || {};
39
41
  const { pg = pgClients.client, params = {}, query = {}, headers = {} } = req;
40
42
  const user = req.user || {};
41
43
  const { type, id } = params;
@@ -46,7 +48,7 @@ export default async function getContent(req, reply, called = false) {
46
48
 
47
49
  const { draftKey } = await getDraftKey();
48
50
  const showDrafts = query.draftKey && query.draftKey === draftKey;
49
- const statusQuery = !!req.user?.uid || showDrafts || called ? '1=1' : `status='published'`;
51
+ const statusQuery = !!req.user?.uid || showDrafts || showDrafts1 ? '1=1' : `status='published'`;
50
52
 
51
53
  // headers.authorization = 'Bearer tokenExample'
52
54
  const isValidToken = await pg.query(
@@ -63,7 +65,7 @@ export default async function getContent(req, reply, called = false) {
63
65
  }
64
66
 
65
67
  const { contentId, contentTypeId, meta } = params.type === 'pages'
66
- ? await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where content_id=$1`, [params.type]).then(el => el.rows?.[0] || {})
68
+ ? { contentId: params.id || 'pages', contentTypeId: params.id || 'pages', meta: null }
67
69
  : await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where $1 in (slug, content_id, content_type_id)`, [params.type]).then(el => el.rows?.[0] || {});
68
70
 
69
71
  if (!contentId) {
@@ -86,7 +88,7 @@ export default async function getContent(req, reply, called = false) {
86
88
 
87
89
  defaultColumns.forEach(col => Object.assign(col, { default: true }));
88
90
 
89
- const columns = columns1.filter(col => !defaultColumns.map(el => el.name).includes(col.name));
91
+ const columns = (columns1 || []).filter(col => !defaultColumns.map(el => el.name).includes(col.name));
90
92
 
91
93
  const result = contentType === 'collection' && table
92
94
  ? await getCollection({
@@ -1,16 +1,16 @@
1
- import { pgClients } from '@opengis/fastify-table/utils.js';
2
-
3
- export default async function getPermissions(req, reply) {
4
- const { pg = pgClients.client, params = {}, user = {} } = req;
5
-
6
- if (!user?.uid) {
7
- return reply.status(401).send('unauthorized');
8
- }
9
-
10
- const { rows = [] } = await pg.query(
11
- `select * from site.permissions where ${params.id ? 'user_id=$1' : 'true'}`,
12
- [params.id].filter(Boolean),
13
- );
14
-
15
- return { permissions: rows };
1
+ import { pgClients } from '@opengis/fastify-table/utils.js';
2
+
3
+ export default async function getPermissions(req, reply) {
4
+ const { pg = pgClients.client, params = {}, user = {} } = req;
5
+
6
+ if (!user?.uid) {
7
+ return reply.status(401).send('unauthorized');
8
+ }
9
+
10
+ const { rows = [] } = await pg.query(
11
+ `select * from site.permissions where ${params.id ? 'user_id=$1' : 'true'}`,
12
+ [params.id].filter(Boolean),
13
+ );
14
+
15
+ return { permissions: rows };
16
16
  }
@@ -1,50 +1,50 @@
1
- import { logger, pgClients, dataInsert } from '@opengis/fastify-table/utils.js';
2
-
3
- export default async function setPermissions(req, reply) {
4
- const { pg = pgClients.client, params = {}, user = {}, body = {} } = req;
5
-
6
- if (!user?.uid) {
7
- return reply.status(401).send('unauthorized');
8
- }
9
-
10
- if (!params.id) {
11
- return reply.status(400).send('not enough params: id');
12
- }
13
-
14
- const client = await pg.connect()
15
- const result = {};
16
- try {
17
- await client.query('BEGIN');
18
-
19
- const { rowCount = 0 } = await client.query(
20
- `delete from site.permissions where user_id=$1`,
21
- [params.id].filter(Boolean),
22
- );
23
-
24
- Object.assign(result, { deleted: rowCount });
25
-
26
- if (Array.isArray(body.permissions) && body.permissions?.length) {
27
- body.permissions.forEach((el) => {
28
- Object.assign(el, { user_id: el.user_id || params.id });
29
- });
30
-
31
- await Promise.all(body.permissions.map(async (el) => dataInsert({
32
- pg: client,
33
- table: 'site.permissions',
34
- data: el,
35
- uid: user.uid,
36
- })));
37
-
38
- Object.assign(result, { inserted: body.permissions.length });
39
- }
40
-
41
- await client.query('COMMIT');
42
- return reply.status(200).send(result);
43
- } catch (err) {
44
- await client.query('ROLLBACK');
45
- logger.file('cms/permissions', { error: err.toString(), stack: err.stack });
46
- return reply.status(500).send('set permissions error');
47
- } finally {
48
- client.release();
49
- }
1
+ import { logger, pgClients, dataInsert } from '@opengis/fastify-table/utils.js';
2
+
3
+ export default async function setPermissions(req, reply) {
4
+ const { pg = pgClients.client, params = {}, user = {}, body = {} } = req;
5
+
6
+ if (!user?.uid) {
7
+ return reply.status(401).send('unauthorized');
8
+ }
9
+
10
+ if (!params.id) {
11
+ return reply.status(400).send('not enough params: id');
12
+ }
13
+
14
+ const client = await pg.connect()
15
+ const result = {};
16
+ try {
17
+ await client.query('BEGIN');
18
+
19
+ const { rowCount = 0 } = await client.query(
20
+ `delete from site.permissions where user_id=$1`,
21
+ [params.id].filter(Boolean),
22
+ );
23
+
24
+ Object.assign(result, { deleted: rowCount });
25
+
26
+ if (Array.isArray(body.permissions) && body.permissions?.length) {
27
+ body.permissions.forEach((el) => {
28
+ Object.assign(el, { user_id: el.user_id || params.id });
29
+ });
30
+
31
+ await Promise.all(body.permissions.map(async (el) => dataInsert({
32
+ pg: client,
33
+ table: 'site.permissions',
34
+ data: el,
35
+ uid: user.uid,
36
+ })));
37
+
38
+ Object.assign(result, { inserted: body.permissions.length });
39
+ }
40
+
41
+ await client.query('COMMIT');
42
+ return reply.status(200).send(result);
43
+ } catch (err) {
44
+ await client.query('ROLLBACK');
45
+ logger.file('cms/permissions', { error: err.toString(), stack: err.stack });
46
+ return reply.status(500).send('set permissions error');
47
+ } finally {
48
+ client.release();
49
+ }
50
50
  }
@@ -120,17 +120,43 @@ export default async function updateContent(req, reply) {
120
120
  return reply.status(400).send('access restricted: empty/invalid block ' + emptyBlock);
121
121
  }
122
122
 
123
+ const single = await pg.query(
124
+ `select 1 FROM site.contents
125
+ where content_id=$1`, [params.id]
126
+ ).then(el => el.rowCount || 0);
127
+
128
+ const customCtExists = await pg.query(
129
+ `select 1 FROM site.content_types
130
+ where content_type_id=$1`, [params.id]
131
+ ).then(el => el.rowCount || 0);
132
+
123
133
  const client = await pg.connect();
124
134
 
125
135
  try {
126
136
  await client.query('begin');
127
- const res = await dataUpdate({
137
+
138
+ const res = {};
139
+
140
+ if (single && !customCtExists) {
141
+ const res1 = await dataInsert({
142
+ pg: client,
143
+ table: 'site.content_types',
144
+ id: params.id,
145
+ data: body,
146
+ uid: user?.uid,
147
+ });
148
+ Object.assign(res, res1);
149
+ }
150
+
151
+ const res1 = await dataUpdate({
128
152
  pg: client,
129
153
  table: 'site.contents',
130
154
  id,
131
155
  data: { ...body, content_type_id: ctid1 },
132
156
  uid: user?.uid,
133
157
  });
158
+ Object.assign(res, res1);
159
+
134
160
  // if (contentId) {
135
161
  // await client.query(`delete from site.content_data where content_id=$1`, [contentId]);
136
162
  // }
@@ -12,7 +12,7 @@ export default async function getSettings({ entity = 'app', keys = ['cms'], uid
12
12
  return { error: "properties table not found", code: 404 };
13
13
  }
14
14
 
15
- const crudInc = await rclient.get(`pg:admin.properties:crud`) || 0;
15
+ const crudInc = await rclient.get(`pg:${config.pg?.database}:admin.properties:crud`) || 0;
16
16
  const cacheKey = [config.pg?.database, "cms:settings", crudInc, entity, keys, uid].filter(Boolean).join(":");
17
17
  const cache = ttl === 0 ? null : await rclient.get(cacheKey);
18
18
 
@@ -11,16 +11,9 @@ export default async function getSingle({
11
11
  const id = id1 || (contentId1 === 'pages' ? undefined : contentId1) || '';
12
12
  const contentId = id1 ? contentId1 : "pages";
13
13
 
14
- // defaultColumns.push({
15
- // "name": "content_type_id",
16
- // "label": "Тип сторінки",
17
- // "type": "select",
18
- // "data": "cms.page_type"
19
- // });
20
-
21
- const customColumns = await pg.query(`
22
- SELECT columns FROM site.content_types WHERE content_type_id in (select content_type_id from site.contents where content_id=$1) limit 1
23
- `, [id1 || contentId]).then(el => el.rows?.[0]?.columns || []);
14
+ const customColumns = await pg.query(
15
+ `select columns FROM site.content_types where content_type_id=$1`, [id || contentId]
16
+ ).then(el => el.rows?.[0]?.columns || []);
24
17
 
25
18
  const contentQuery = contentId === 'pages' || !id
26
19
  ? `(type = 'single' or content_type_id = 'pages')`
@@ -174,6 +167,9 @@ export default async function getSingle({
174
167
  });
175
168
  });
176
169
 
170
+ // temporary solution, before front makes changes to call by id, not type
171
+ rows1.forEach(row => Object.assign(row, { content_type_id: row.content_id }));
172
+
177
173
  return {
178
174
  locales,
179
175
  type: 'single',
@@ -1,4 +1,4 @@
1
- import { config, dataUpdate, pgClients } from '@opengis/fastify-table/utils.js';
1
+ import { dataInsert, dataUpdate, pgClients } from '@opengis/fastify-table/utils.js';
2
2
 
3
3
  import updateCustomContentTable from '../utils/updateCustomContentTable.js';
4
4
  import updateContents from '../utils/updateContents.js';
@@ -13,12 +13,22 @@ export default async function builderPut(req, reply) {
13
13
  return reply.status(404).send('table not found');
14
14
  }
15
15
 
16
+ const single = await pg.query(
17
+ `select content_id as id FROM site.contents
18
+ where $1 in (content_id, slug)`, [params.id]
19
+ ).then(el => el.rows?.[0]);
20
+
21
+ const customCtExists = await pg.query(
22
+ `select 1 FROM site.content_types
23
+ where content_type_id=$1`, [params.id]
24
+ ).then(el => el.rowCount || 0);
25
+
16
26
  const { cid, table } = await pg.query(
17
27
  `select content_type_id as cid, table_name as table, type from site.content_types where $1 in (content_type_id, name)`,
18
28
  [params.id],
19
29
  ).then(el => el.rows?.[0] || {});
20
30
 
21
- if (!cid) {
31
+ if (!cid && !single) {
22
32
  return reply.status(404).send('content type not found');
23
33
  }
24
34
 
@@ -39,13 +49,23 @@ export default async function builderPut(req, reply) {
39
49
  await updateCustomContentTable({ pg: client, id: cid, columns });
40
50
  }
41
51
 
42
- await dataUpdate({
43
- pg: client,
44
- table: 'site.content_types',
45
- id: cid,
46
- data: body,
47
- uid: user?.uid,
48
- });
52
+ if (single && !customCtExists) {
53
+ await dataInsert({
54
+ pg,
55
+ table: 'site.content_types',
56
+ id: params.id,
57
+ data: body,
58
+ uid: user?.uid,
59
+ });
60
+ } else {
61
+ await dataUpdate({
62
+ pg: client,
63
+ table: 'site.content_types',
64
+ id: cid,
65
+ data: body,
66
+ uid: user?.uid,
67
+ });
68
+ }
49
69
 
50
70
  const row = await updateContents(client, cid, { ...body, slug: body.slug || body.name }, user?.uid);
51
71
 
@@ -9,11 +9,24 @@ export default async function builderGet({ pg = pgClients.client, params = {} },
9
9
  return reply.status(404).send('table not found');
10
10
  }
11
11
 
12
+ const single = await pg.query(
13
+ `select content_id as id, * FROM site.contents
14
+ where $1 in (content_id, slug)`, [params.id]
15
+ ).then(el => el.rows?.[0]);
16
+
12
17
  const row = await pg.query(
13
18
  `select content_type_id as id, * FROM site.content_types
14
19
  where $1 in (content_type_id, name)`, [params.id]
15
20
  ).then(el => el.rows?.[0]);
16
21
 
22
+ if (single && !row) {
23
+ const loadTable = await getTemplate('table', 'single.default.table');
24
+ const { columns: defaultColumns } = loadTable || {};
25
+ (defaultColumns || []).forEach(col => Object.assign(col, { default: true }));
26
+ const columns = (defaultColumns || []).filter(col => !col.hidden);
27
+ return reply.status(200).send({ default: true, id: single.id, name: single.slug, type: 'single', ...single, columns });
28
+ }
29
+
17
30
  if (!row) {
18
31
  return reply.status(404).send('content type not found');
19
32
  }
@@ -19,6 +19,22 @@ export default async function updateContents(pg, id, data, uid) {
19
19
  return result;
20
20
  }
21
21
 
22
+ const single = await pg.query(
23
+ `select content_id from site.contents where content_id=$1`,
24
+ [id],
25
+ ).then(el => el.rowCount || 0);
26
+
27
+ if (single) {
28
+ const result = await dataUpdate({
29
+ pg,
30
+ table: 'site.contents',
31
+ id,
32
+ data,
33
+ uid,
34
+ });
35
+ return result;
36
+ }
37
+
22
38
  const result = await dataInsert({
23
39
  pg,
24
40
  table: 'site.contents',
@@ -10,7 +10,7 @@ export default async function getMenuAPI(req, reply) {
10
10
  page: query.page,
11
11
  limit: Math.min(query.limit || limit, limit),
12
12
  sql: query.sql,
13
- ttl: 3600
13
+ ttl: 0
14
14
  });
15
15
 
16
16
  if (result.error) {
@@ -21,5 +21,5 @@ export default async function getMenuAPI(req, reply) {
21
21
  return reply.status(200).send(result);
22
22
  }
23
23
 
24
- return reply.status(200).send({ rows: result.rows });
24
+ return reply.status(200).send({ cache: result.cache, rows: result.rows });
25
25
  }
@@ -14,8 +14,8 @@ export default async function getMenu(name, { locale, ttl = 3600, page, limit =
14
14
  return { error: 'table not found', code: 404 };
15
15
  }
16
16
 
17
- const crudInc = await rclient.get(`pg:site.menus:crud`) || 0;
18
- const cacheKey = createHash('md5').update([config.pg?.database, 'cms:menu', crudInc, name, locale].filter(Boolean).join(':')).digest('hex');
17
+ const crudInc = await rclient.get(`pg:${config.pg?.database}:site.menus:crud`) || 0;
18
+ const cacheKey = createHash('md5').update([config.pg?.database, 'cms:menu', crudInc, name, locale, page, limit].filter(Boolean).join(':')).digest('hex');
19
19
 
20
20
  const cache = ttl === 0 ? null : await rclient.get(cacheKey);
21
21
 
@@ -46,5 +46,5 @@ export default async function getMenu(name, { locale, ttl = 3600, page, limit =
46
46
  // save to cache, default = 1 hour
47
47
  if (ttl) await rclient.set(cacheKey, JSON.stringify(payload), 'EX', ttl);
48
48
 
49
- return payload;
49
+ return { cache: false, ...payload };
50
50
  }
@@ -1,2 +1,2 @@
1
- select uid, coalesce(sur_name,'')||coalesce(' '||user_name,'') as text, email from admin.users
1
+ select uid, coalesce(sur_name,'')||coalesce(' '||user_name,'') as text, email from admin.users
2
2
  where enabled order by coalesce(sur_name,'')||coalesce(' '||user_name,'')