@opengis/cms 0.0.2 → 0.0.3

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 (144) hide show
  1. package/.gitlab-ci.yml +36 -0
  2. package/config.example +21 -0
  3. package/docs/.vitepress/abbr.mjs +26 -0
  4. package/docs/.vitepress/config.mjs +119 -0
  5. package/docs/.vitepress/navigation.mjs +82 -0
  6. package/docs/.vitepress/theme/Layout.vue +17 -0
  7. package/docs/.vitepress/theme/components/NavigationLinks.vue +102 -0
  8. package/docs/.vitepress/theme/components/Panzoom.vue +169 -0
  9. package/docs/.vitepress/theme/index.mjs +15 -0
  10. package/docs/.vitepress/theme/style.scss +136 -0
  11. package/docs/abbr.json +4 -0
  12. package/docs/api/builder/cms.builder.delete.md +65 -0
  13. package/docs/api/builder/cms.builder.get.md +70 -0
  14. package/docs/api/builder/cms.builder.list.md +98 -0
  15. package/docs/api/builder/cms.builder.post.md +72 -0
  16. package/docs/api/builder/cms.builder.put.md +88 -0
  17. package/docs/api/category/cms.category.delete.md +60 -0
  18. package/docs/api/category/cms.category.get.md +61 -0
  19. package/docs/api/category/cms.category.list.md +77 -0
  20. package/docs/api/category/cms.category.post.md +62 -0
  21. package/docs/api/category/cms.category.put.md +78 -0
  22. package/docs/api/index.md +50 -0
  23. package/docs/api/manager/cms.manager.delete.md +64 -0
  24. package/docs/api/manager/cms.manager.get.md +72 -0
  25. package/docs/api/manager/cms.manager.list.md +96 -0
  26. package/docs/api/manager/cms.manager.post.md +70 -0
  27. package/docs/api/manager/cms.manager.put.md +86 -0
  28. package/docs/api/media/del.md +64 -0
  29. package/docs/api/media/edit.md +92 -0
  30. package/docs/api/media/list.md +70 -0
  31. package/docs/api/media/metadata.md +57 -0
  32. package/docs/api/media/preview.md +33 -0
  33. package/docs/api/media/upload.md +84 -0
  34. package/docs/db/erd.md +173 -0
  35. package/docs/db/index.md +7 -0
  36. package/docs/index.md +39 -0
  37. package/docs/public/logo-dark.svg +24 -0
  38. package/docs/public/logo-light.svg +24 -0
  39. package/docs/public/logo-short.svg +15 -0
  40. package/docs/public/logo.svg +19 -0
  41. package/docs/readme/index.md +6 -0
  42. package/docs/src/vs-button.vue +157 -0
  43. package/docs/vue/basic/button.md +144 -0
  44. package/docs/vue/index.md +9 -0
  45. package/index.html +14 -0
  46. package/package.json +2 -5
  47. package/server/app.js +25 -0
  48. package/server/config.js +5 -0
  49. package/server/index.js +23 -0
  50. package/server/migrations/media.sql +30 -0
  51. package/server/plugins/hook.js +91 -0
  52. package/server/plugins/vite.js +80 -0
  53. package/server/routes/builder/controllers/cms.builder.delete.js +21 -0
  54. package/server/routes/builder/controllers/cms.builder.get.js +17 -0
  55. package/server/routes/builder/controllers/cms.builder.list.js +16 -0
  56. package/server/routes/builder/controllers/cms.builder.post.js +21 -0
  57. package/server/routes/builder/controllers/cms.builder.put.js +23 -0
  58. package/server/routes/builder/index.mjs +22 -0
  59. package/server/routes/category/controllers/cms.category.delete.js +21 -0
  60. package/server/routes/category/controllers/cms.category.get.js +17 -0
  61. package/server/routes/category/controllers/cms.category.list.js +16 -0
  62. package/server/routes/category/controllers/cms.category.post.js +21 -0
  63. package/server/routes/category/controllers/cms.category.put.js +23 -0
  64. package/server/routes/category/index.mjs +22 -0
  65. package/server/routes/manager/controllers/cms.manager.delete.js +22 -0
  66. package/server/routes/manager/controllers/cms.manager.get.js +21 -0
  67. package/server/routes/manager/controllers/cms.manager.list.js +31 -0
  68. package/server/routes/manager/controllers/cms.manager.post.js +28 -0
  69. package/server/routes/manager/controllers/cms.manager.put.js +23 -0
  70. package/server/routes/manager/index.mjs +22 -0
  71. package/server/routes/media/controllers/delete.js +59 -0
  72. package/server/routes/media/controllers/edit.js +94 -0
  73. package/server/routes/media/controllers/list.js +74 -0
  74. package/server/routes/media/controllers/metadata.js +51 -0
  75. package/server/routes/media/controllers/preview.js +47 -0
  76. package/server/routes/media/controllers/upload.js +79 -0
  77. package/server/routes/media/index.mjs +16 -0
  78. package/server/routes/root.mjs +15 -0
  79. package/server/templates/cls/cms.category_type.json +10 -0
  80. package/server/templates/cls/cms.content_review_status.json +10 -0
  81. package/server/templates/cls/cms.content_status.json +10 -0
  82. package/server/templates/cls/cms.content_type.json +10 -0
  83. package/server/templates/cls/cms.lang.json +10 -0
  84. package/server/templates/page/login.html +59 -0
  85. package/server/templates/select/cms.category_id.sql +1 -0
  86. package/server/templates/select/cms.type_id.sql +1 -0
  87. package/src/App.vue +4 -0
  88. package/src/assets/tailwind/tailwind.js +62 -0
  89. package/src/assets/vue.svg +1 -0
  90. package/src/components/builder/vs-builder-content.vue +163 -0
  91. package/src/components/builder/vs-builder-menu.vue +142 -0
  92. package/src/components/formats/index.js +8 -0
  93. package/src/components/formats/vs-manager-table-date.vue +29 -0
  94. package/src/components/formats/vs-manager-table-switch.vue +16 -0
  95. package/src/components/icons/icon-actions.vue +24 -0
  96. package/src/components/icons/icon-arrow-left.vue +19 -0
  97. package/src/components/icons/icon-check.vue +23 -0
  98. package/src/components/icons/icon-chewron-right.vue +16 -0
  99. package/src/components/icons/icon-close.vue +22 -0
  100. package/src/components/icons/icon-edit.vue +22 -0
  101. package/src/components/icons/icon-folder.vue +18 -0
  102. package/src/components/icons/icon-folder2.vue +17 -0
  103. package/src/components/icons/icon-home.vue +16 -0
  104. package/src/components/icons/icon-image.vue +18 -0
  105. package/src/components/icons/icon-logo.vue +22 -0
  106. package/src/components/icons/icon-media.vue +22 -0
  107. package/src/components/icons/icon-point.vue +11 -0
  108. package/src/components/icons/icon-search.vue +22 -0
  109. package/src/components/icons/icon-table.vue +22 -0
  110. package/src/components/icons/icon-users.vue +18 -0
  111. package/src/components/icons/icon.plus.vue +18 -0
  112. package/src/components/manager/children/vs-manager-collection-content.vue +55 -0
  113. package/src/components/manager/children/vs-manager-collection-item-content.vue +116 -0
  114. package/src/components/manager/children/vs-manager-single-content.vue +112 -0
  115. package/src/components/manager/manager-table/vs-manager-colection-table-add.vue +84 -0
  116. package/src/components/manager/manager-table/vs-manager-collection-table.vue +59 -0
  117. package/src/components/manager/vs-manager-menu.vue +73 -0
  118. package/src/components/media/Breadcrumb.vue +73 -0
  119. package/src/components/shared-components/vs-not-data.vue +213 -0
  120. package/src/components/vs-main-menu.vue +53 -0
  121. package/src/helpers/debounce.js +10 -0
  122. package/src/helpers/translite.js +19 -0
  123. package/src/main.js +30 -0
  124. package/src/misc/import-file.js +32 -0
  125. package/src/pages/vs-builder.vue +22 -0
  126. package/src/pages/vs-layout.vue +17 -0
  127. package/src/pages/vs-manager.vue +30 -0
  128. package/src/pages/vs-media.vue +398 -0
  129. package/src/router/router.js +9 -0
  130. package/src/router/routes.config.js +40 -0
  131. package/src/style.css +0 -0
  132. package/src/templates/form-columns.js +70 -0
  133. package/src/templates/form-template.js +22 -0
  134. package/test/config.js +17 -0
  135. package/test/files/eye.svg +4 -0
  136. package/test/helper.js +30 -0
  137. package/test/routes/builder.test.js +99 -0
  138. package/test/routes/category.test.js +97 -0
  139. package/test/routes/manager.test.js +103 -0
  140. package/test/routes/media.test.js +252 -0
  141. package/vite.config.js +37 -0
  142. package/editor/dist/cms.js +0 -5900
  143. package/editor/dist/cms.umd.cjs +0 -19
  144. /package/{editor/dist → public}/vite.svg +0 -0
@@ -0,0 +1,47 @@
1
+ import path from 'node:path';
2
+ import { existsSync } from 'node:fs';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ import { config, getToken, getFolder } from "@opengis/fastify-table/utils.js";
6
+ import { getMimeType } from '@opengis/fastify-file/utils.js';
7
+
8
+ const rootDir = getFolder(config, 'local');
9
+
10
+ export default async function deleteMedia({
11
+ params = {}, query = {}, user = {},
12
+ }, reply) {
13
+
14
+ if (!params?.token) {
15
+ return reply.status(400).send('not enough params: token');
16
+ }
17
+
18
+ const tokenData = await getToken({
19
+ uid: user?.uid || 0,
20
+ token: params.token,
21
+ json: 1,
22
+ });
23
+
24
+ const { relpath } = tokenData || {};
25
+
26
+ if (!relpath) {
27
+ return reply.status(403).send('invalid token');
28
+ }
29
+
30
+ const filepath = path.join(rootDir, relpath);
31
+
32
+ if (!existsSync(filepath)) {
33
+ return reply.status(404).send('file not found');
34
+ }
35
+
36
+ const buffer = await readFile(filepath, { buffer: true });
37
+
38
+ if (query?.download) {
39
+ const headers = {
40
+ 'Content-Type': getMimeType(filepath),
41
+ 'Content-Disposition': `attachment; filename=${path.basename(filepath)}`
42
+ };
43
+ return reply.headers(headers).send(buffer);
44
+ }
45
+
46
+ return reply.headers({ 'Content-Type': getMimeType(filepath) }).send(buffer);
47
+ }
@@ -0,0 +1,79 @@
1
+ import path from 'node:path';
2
+ import { mkdir, rename } from 'node:fs/promises';
3
+
4
+ import { config, getToken, getFolder, setToken, dataInsert } from "@opengis/fastify-table/utils.js";
5
+ import { uploadMultiPart } from '@opengis/fastify-file/utils.js';
6
+
7
+ const rootDir = getFolder(config, 'local');
8
+
9
+ export default async function uploadMedia(req, reply) {
10
+ const { params = {}, user = {}, body = {} } = req;
11
+
12
+ if (!params.token) {
13
+ return reply.status(400).send('not enough params: token');
14
+ }
15
+
16
+ const tokenData = await getToken({
17
+ uid: user?.uid || 0,
18
+ token: params.token,
19
+ json: 1,
20
+ });
21
+
22
+ if (!tokenData) {
23
+ return reply.status(403).send('invalid params: token');
24
+ }
25
+
26
+ const { name: dirname } = tokenData;
27
+
28
+ // upload assets
29
+ if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
30
+ const file = await uploadMultiPart(req);
31
+ const filename = `${file.newFilename}${path.extname(file.filepath)}`;
32
+ const newfilepath = path.join(rootDir, 'media', dirname || '', filename);
33
+ // console.log(file.filepath, newfilepath);
34
+ await rename(file.filepath, newfilepath);
35
+
36
+ const id = await dataInsert({
37
+ table: 'crm.media',
38
+ data: {
39
+ uploaded_name: file.originalFilename,
40
+ file_path: path.join('/media', dirname || '', filename).replace(/\\/g, '/'),
41
+ ext: path.extname(file.filepath)?.split('.')?.pop?.(),
42
+ size: file.size,
43
+ },
44
+ uid: user?.uid || 0,
45
+ }).then(el => el?.rows?.[0]?.media_id);
46
+ const result = {
47
+ dir: dirname,
48
+ id,
49
+ name: filename,
50
+ type: 'file',
51
+ token: setToken({
52
+ ids: [JSON.stringify({ id, dir: dirname, relpath: path.join('/media', dirname || '', filename).replace(/\\/g, '/'), name: filename, type: 'file' })],
53
+ uid: user?.uid || 0,
54
+ array: 1,
55
+ })[0],
56
+ };
57
+ return reply.status(200).send(result);
58
+ }
59
+
60
+ // create directory
61
+ if (!body?.name || typeof body.name !== 'string' || body.name.includes('..')) {
62
+ return reply.status(400).send('invalid body params: name');
63
+ }
64
+
65
+ const subdir = path.join('/media', dirname || '', body.name).replace(/\\/g, '/');
66
+ const dirpath = path.join(rootDir, subdir);
67
+ await mkdir(dirpath, { recursive: true });
68
+
69
+ return reply.status(200).send({
70
+ dir: subdir,
71
+ name: body.name,
72
+ type: 'dir',
73
+ token: setToken({
74
+ ids: [JSON.stringify({ relpath: subdir, name: body.name, type: 'dir' })],
75
+ uid: user?.uid || 0,
76
+ array: 1,
77
+ })[0],
78
+ });
79
+ }
@@ -0,0 +1,16 @@
1
+ import list from './controllers/list.js';
2
+ import metadata from './controllers/metadata.js';
3
+ import upload from './controllers/upload.js';
4
+ import edit from './controllers/edit.js';
5
+ import del from './controllers/delete.js';
6
+ import preview from './controllers/preview.js';
7
+
8
+ export default async function route(app) {
9
+ app.get('/cms-media', { config: { policy: ['site'] } }, list);
10
+ app.get('/cms-media/:token', { config: { policy: ['site'] } }, preview);
11
+ app.post('/cms-media/:token', { config: { policy: ['site'] } }, upload); // upload file / create empty dir
12
+
13
+ app.get('/cms-media-metadata/:token', { config: { policy: ['site'] } }, metadata);
14
+ app.put('/cms-media/:token', { config: { policy: ['site'] } }, edit);
15
+ app.delete('/cms-media/:token', { config: { policy: ['site'] } }, del);
16
+ }
@@ -0,0 +1,15 @@
1
+ 'use strict'
2
+
3
+ const schema = {
4
+ querystring: {
5
+ name: { type: 'string', pattern: "^(\\d+)$" },
6
+ token: { type: 'string', pattern: "^(\\d+)$" },
7
+ },
8
+ }
9
+
10
+ export default async function (fastify, opts) {
11
+ fastify.get('/test', async function (request, reply) {
12
+ return { root: true }
13
+ });
14
+
15
+ }
@@ -0,0 +1,10 @@
1
+ [
2
+ {
3
+ "id": "1",
4
+ "text": "Important"
5
+ },
6
+ {
7
+ "id": "2",
8
+ "text": "Common"
9
+ }
10
+ ]
@@ -0,0 +1,10 @@
1
+ [
2
+ {
3
+ "id": "1",
4
+ "text": "Pending"
5
+ },
6
+ {
7
+ "id": "2",
8
+ "text": "Approved"
9
+ }
10
+ ]
@@ -0,0 +1,10 @@
1
+ [
2
+ {
3
+ "id": "1",
4
+ "text": "Draft"
5
+ },
6
+ {
7
+ "id": "2",
8
+ "text": "Publish"
9
+ }
10
+ ]
@@ -0,0 +1,10 @@
1
+ [
2
+ {
3
+ "id": "1",
4
+ "text": "Single"
5
+ },
6
+ {
7
+ "id": "2",
8
+ "text": "Collection"
9
+ }
10
+ ]
@@ -0,0 +1,10 @@
1
+ [
2
+ {
3
+ "id": "uk",
4
+ "text": "Українська"
5
+ },
6
+ {
7
+ "id": "en",
8
+ "text": "English"
9
+ }
10
+ ]
@@ -0,0 +1,59 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" dir="">
3
+
4
+ <head>
5
+ <!-- scripts -->
6
+ <script src="https://cdn.tailwindcss.com"></script>
7
+ </head>
8
+
9
+ <body class="bg-[#f3f4f6] flex items-center flex-1 w-full h-[100vh] overflow-x-hidden min-h-full ">
10
+ <main class="w-full">
11
+ <div class="flex w-full max-w-sm mx-auto overflow-hidden bg-white rounded-lg shadow-lg dark:bg-gray-800 lg:max-w-4xl">
12
+ <div class="hidden bg-cover lg:block lg:w-1/2 bg-center" style="background-image: url('https://nipo.gov.ua/wp-content/uploads/2023/02/Pro_nas_2301-768x512.jpg');"></div>
13
+
14
+ <div class="w-full px-6 py-8 md:px-8 lg:w-1/2">
15
+ <div class="flex justify-center mx-auto">
16
+ <img class="w-auto h-7 sm:h-16" src="https://nipo.gov.ua/wp-content/uploads/2023/01/IP_office_logo_UA-1-1.png" alt="logo">
17
+ </div>
18
+
19
+ <p class="mt-3 mb-[32px] text-xl text-center text-gray-600 dark:text-gray-200">
20
+ Український національний офіс інтелектуальної власності та інновацій
21
+ </p>
22
+
23
+ <form action="/api/login" method="get" >
24
+ <div class="mt-4">
25
+ <label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-200" for="LoggingEmailAddress">Електронна пошта / Логін</label>
26
+ <input name="username" id="LoggingEmailAddress" class="block w-full px-4 py-2 text-gray-700 bg-white border rounded-lg dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 focus:ring-opacity-40 dark:focus:border-blue-300 focus:outline-none focus:ring focus:ring-blue-300" type="text">
27
+ </div>
28
+
29
+ <div class="mt-4">
30
+ <div class="flex justify-between">
31
+ <label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-200" for="loggingPassword">Пароль</label>
32
+ <!-- <a class="text-xs text-gray-500 dark:text-gray-300 hover:underline">Forget Password?</a> -->
33
+ </div>
34
+
35
+ <input id="loggingPassword" name="password" class="block w-full px-4 py-2 text-gray-700 bg-white border rounded-lg dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 focus:ring-opacity-40 dark:focus:border-blue-300 focus:outline-none focus:ring focus:ring-blue-300" type="password">
36
+ </div>
37
+
38
+ <div class="mt-6">
39
+ <button type="submit" class="w-full px-6 py-3 text-sm font-medium tracking-wide text-white capitalize transition-colors duration-300 transform bg-gray-800 rounded-lg hover:bg-gray-700 focus:outline-none focus:ring focus:ring-gray-300 focus:ring-opacity-50">
40
+ Увійти
41
+ </button>
42
+ </div>
43
+
44
+ </form>
45
+ </div>
46
+ </div>
47
+ </main>
48
+
49
+ </body>
50
+
51
+
52
+ <script>
53
+ const error = location.search.includes('wrong_pass')
54
+ if (error) {
55
+ document.getElementById('login_error').innerHTML = 'Не вірний користувач або пароль';
56
+ }
57
+ </script>
58
+
59
+ </html>
@@ -0,0 +1 @@
1
+ select category_id, title from site.categories
@@ -0,0 +1 @@
1
+ select content_type_id, name from site.content_types
package/src/App.vue ADDED
@@ -0,0 +1,4 @@
1
+ <template>
2
+ <router-view> </router-view>
3
+ <!-- test comit -->
4
+ </template>