@silexlabs/silex 3.0.1-alpha.0 → 3.0.2
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.
- package/.env.default +20 -0
- package/.silex.js +67 -8
- package/LICENSE +661 -203
- package/README.md +37 -35
- package/dist/client/client/api.d.ts +90 -0
- package/dist/client/client/assetUrl.d.ts +54 -0
- package/dist/client/client/config.d.ts +102 -0
- package/dist/client/client/events.d.ts +23 -0
- package/dist/client/client/expose.d.ts +8 -0
- package/dist/client/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/client/client/grapesjs/PublicationManager.d.ts +73 -0
- package/dist/client/client/grapesjs/PublicationUi.d.ts +59 -0
- package/dist/client/client/grapesjs/blocks.d.ts +1 -0
- package/dist/client/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/client/grapesjs/img.d.ts +6 -0
- package/dist/client/client/grapesjs/index.d.ts +9 -0
- package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/client/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/client/client/grapesjs/openImport.d.ts +9 -0
- package/dist/client/client/grapesjs/page-panel.d.ts +9 -0
- package/dist/client/client/grapesjs/project-bar.d.ts +21 -0
- package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/client/grapesjs/rich-text.d.ts +4 -0
- package/dist/client/client/grapesjs/semantic.d.ts +1 -0
- package/dist/client/client/grapesjs/settings-sections.d.ts +16 -0
- package/dist/client/client/grapesjs/settings.d.ts +4 -0
- package/dist/client/client/grapesjs/storage.d.ts +2 -0
- package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/client/index.d.ts +10 -0
- package/dist/client/client/publication-transformers.d.ts +42 -0
- package/dist/client/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/client/publish-fonts.d.ts +4 -0
- package/dist/client/client/utils.d.ts +22 -0
- package/dist/client/constants.d.ts +32 -0
- package/dist/client/css/admin.css +1114 -328
- package/dist/client/css/admin.css.map +1 -0
- package/dist/client/grapesjs-filter-styles/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/src/commands.d.ts +3 -0
- package/dist/client/grapesjs-fonts/src/fonts.d.ts +4 -0
- package/dist/client/grapesjs-storage-rate-limit/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-ui-suggest-classes/dist/index.d.ts +4 -0
- package/dist/client/index.html +3 -2
- package/dist/client/js/main.js +356 -131
- package/dist/client/js/main.js.LICENSE.txt +15 -1
- package/dist/client/page.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/api.d.ts +90 -0
- package/dist/client/silex-lib/src/ts/client/assetUrl.d.ts +54 -0
- package/dist/client/silex-lib/src/ts/client/config.d.ts +102 -0
- package/dist/client/silex-lib/src/ts/client/events.d.ts +23 -0
- package/dist/client/silex-lib/src/ts/client/expose.d.ts +8 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationManager.d.ts +73 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationUi.d.ts +59 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/blocks.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/img.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/index.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/openImport.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/page-panel.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/project-bar.d.ts +21 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/rich-text.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/semantic.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings-sections.d.ts +16 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/storage.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/index.d.ts +10 -0
- package/dist/client/silex-lib/src/ts/client/publication-transformers.d.ts +42 -0
- package/dist/client/silex-lib/src/ts/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/publish-fonts.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/utils.d.ts +22 -0
- package/dist/client/silex-lib/src/ts/constants.d.ts +32 -0
- package/dist/client/silex-lib/src/ts/page.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/types.d.ts +339 -0
- package/dist/client/types.d.ts +339 -0
- package/dist/plugins/client/client/events.d.ts +23 -0
- package/dist/plugins/client/client/events.js +43 -0
- package/dist/plugins/client/client/events.js.map +1 -0
- package/dist/plugins/client/plugins/client/template.d.ts +2 -0
- package/dist/plugins/client/plugins/client/template.js +234 -0
- package/dist/plugins/client/plugins/client/template.js.map +1 -0
- package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
- package/dist/plugins/client/plugins/client/website-info.js +72 -0
- package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
- package/dist/plugins/client/types.d.ts +339 -0
- package/dist/plugins/client/types.js +80 -0
- package/dist/plugins/client/types.js.map +1 -0
- package/dist/plugins/server/constants.d.ts +32 -0
- package/dist/plugins/server/constants.js +76 -0
- package/dist/plugins/server/constants.js.map +1 -0
- package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
- package/dist/plugins/server/plugins/server/Cache.js +36 -0
- package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js +127 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
- package/dist/plugins/server/plugins/server/FtpConnector.js +536 -0
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +135 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.js +649 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.d.ts +16 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js +209 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
- package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
- package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
- package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +8 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.js +45 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
- package/dist/plugins/server/server/config.d.ts +59 -0
- package/dist/plugins/server/server/config.js +181 -0
- package/dist/plugins/server/server/config.js.map +1 -0
- package/dist/plugins/server/server/connectors/FsHosting.d.ts +14 -0
- package/dist/plugins/server/server/connectors/FsHosting.js +66 -0
- package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
- package/dist/plugins/server/server/connectors/FsStorage.d.ts +44 -0
- package/dist/plugins/server/server/connectors/FsStorage.js +261 -0
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
- package/dist/plugins/server/server/connectors/connectors.d.ts +86 -0
- package/dist/plugins/server/server/connectors/connectors.js +126 -0
- package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
- package/dist/plugins/server/server/events.d.ts +26 -0
- package/dist/plugins/server/server/events.js +31 -0
- package/dist/plugins/server/server/events.js.map +1 -0
- package/dist/plugins/server/server/jobs.d.ts +12 -0
- package/dist/plugins/server/server/jobs.js +79 -0
- package/dist/plugins/server/server/jobs.js.map +1 -0
- package/dist/plugins/server/server/utils/validation.d.ts +7 -0
- package/dist/plugins/server/server/utils/validation.js +37 -0
- package/dist/plugins/server/server/utils/validation.js.map +1 -0
- package/dist/plugins/server/types.d.ts +339 -0
- package/dist/plugins/server/types.js +84 -0
- package/dist/plugins/server/types.js.map +1 -0
- package/dist/server/constants.js +55 -0
- package/dist/server/plugins/server/Cache.js +19 -0
- package/dist/server/server/api/api.js +20 -0
- package/dist/server/server/api/connectorApi.js +334 -0
- package/dist/server/server/api/publicationApi.js +106 -0
- package/dist/server/server/api/websiteApi.js +315 -0
- package/dist/server/server/cli.js +71 -0
- package/dist/server/server/config.js +120 -0
- package/dist/server/server/connectors/FsHosting.js +47 -0
- package/dist/server/server/connectors/FsStorage.js +228 -0
- package/dist/server/server/connectors/connectors.js +88 -0
- package/dist/server/server/events.js +14 -0
- package/dist/server/server/expose.js +27 -0
- package/dist/server/server/express.js +46 -0
- package/dist/server/server/index.js +92 -0
- package/dist/server/server/jobs.js +50 -0
- package/dist/server/server/utils/validation.js +14 -0
- package/dist/server/types.js +40 -0
- package/package.json +99 -49
- package/public/assets/download.png +0 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/favicon.png +0 -0
- package/public/assets/ftp.png +0 -0
- package/public/assets/gitlab.png +0 -0
- package/public/assets/gitlab2.png +0 -0
- package/public/assets/laptop.png +0 -0
- package/public/assets/logo-silex-small.png +0 -0
- package/public/silex.js +22 -23
- package/src/css/_variables.scss +24 -20
- package/src/css/dialog.scss +35 -2
- package/src/css/fonts.scss +31 -0
- package/src/css/footer.scss +12 -0
- package/src/css/grapesjs-light.scss +180 -0
- package/src/css/grapesjs-plugins.scss +227 -0
- package/src/css/grapesjs.scss +159 -1
- package/src/css/index.scss +12 -1
- package/src/css/light.scss +7 -0
- package/src/css/loader.scss +2 -0
- package/src/css/project-bar.scss +32 -16
- package/src/css/silex.scss +79 -5
- package/src/css/website-info.scss +14 -0
- package/src/html/index.pug +3 -3
- package/src/html/templates/includes.pug +0 -1
- package/src/ts/client/api.ts +156 -0
- package/src/ts/client/assetUrl.test.ts +164 -0
- package/src/ts/client/assetUrl.ts +254 -0
- package/src/ts/client/config.ts +175 -13
- package/src/ts/client/events.ts +43 -0
- package/src/ts/client/expose.ts +27 -1
- package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
- package/src/ts/client/grapesjs/PublicationManager.ts +433 -0
- package/src/ts/client/grapesjs/PublicationUi.ts +366 -0
- package/src/ts/client/grapesjs/blocks.ts +17 -0
- package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
- package/src/ts/client/grapesjs/css-props.ts +910 -0
- package/src/ts/client/grapesjs/eleventy.ts +30 -7
- package/src/ts/client/grapesjs/footer.ts +42 -0
- package/src/ts/client/grapesjs/img.ts +147 -0
- package/src/ts/client/grapesjs/index.ts +311 -122
- package/src/ts/client/grapesjs/internal-links.test.ts +19 -1
- package/src/ts/client/grapesjs/internal-links.ts +31 -7
- package/src/ts/client/grapesjs/keymaps.ts +207 -0
- package/src/ts/client/grapesjs/new-page-dialog.ts +19 -3
- package/src/ts/client/grapesjs/openImport.ts +22 -0
- package/src/ts/client/grapesjs/page-panel.ts +109 -7
- package/src/ts/client/grapesjs/project-bar.ts +133 -72
- package/src/ts/client/grapesjs/resize-panel.ts +20 -0
- package/src/ts/client/grapesjs/rich-text.ts +38 -13
- package/src/ts/client/grapesjs/semantic.ts +20 -3
- package/src/ts/client/grapesjs/settings-sections.ts +117 -0
- package/src/ts/client/grapesjs/settings.ts +191 -96
- package/src/ts/client/grapesjs/storage.ts +187 -0
- package/src/ts/client/grapesjs/symbolDialogs.ts +21 -5
- package/src/ts/client/grapesjs/view-buttons.ts +42 -0
- package/src/ts/client/index.ts +80 -21
- package/src/ts/client/publication-transformers.test.ts +207 -0
- package/src/ts/client/publication-transformers.ts +280 -0
- package/src/ts/client/publish-custom-code-block.ts +31 -0
- package/src/ts/client/publish-fonts.ts +36 -0
- package/src/ts/client/utils.ts +70 -1
- package/src/ts/constants.ts +78 -0
- package/src/ts/externs.ts +17 -0
- package/src/ts/page.ts +20 -3
- package/src/ts/plugins/client/template.ts +246 -0
- package/src/ts/plugins/client/website-info.ts +84 -0
- package/src/ts/plugins/server/Cache.ts +32 -0
- package/src/ts/plugins/server/DownloadConnector.ts +146 -0
- package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
- package/src/ts/plugins/server/FtpConnector.ts +621 -0
- package/src/ts/plugins/server/GitlabConnector.ts +749 -0
- package/src/ts/plugins/server/GitlabHostingConnector.ts +215 -0
- package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
- package/src/ts/plugins/server/SslPlugin.ts +84 -0
- package/src/ts/plugins/server/StaticPlugin.ts +45 -0
- package/src/ts/server/api/api.ts +19 -0
- package/src/ts/server/api/connectorApi.ts +464 -0
- package/src/ts/server/api/publicationApi.ts +159 -0
- package/src/ts/server/api/websiteApi.ts +462 -0
- package/src/ts/server/cli.ts +48 -14
- package/src/ts/server/config.ts +158 -60
- package/src/ts/server/connectors/FsHosting.ts +66 -0
- package/src/ts/server/connectors/FsStorage.test.ts +51 -0
- package/src/ts/server/connectors/FsStorage.ts +290 -0
- package/src/ts/server/connectors/connectors.ts +203 -0
- package/src/ts/server/events.ts +37 -0
- package/src/ts/server/expose.ts +19 -0
- package/src/ts/server/express.ts +57 -5
- package/src/ts/server/index.ts +80 -19
- package/src/ts/server/jobs.test.ts +75 -0
- package/src/ts/server/jobs.ts +89 -0
- package/src/ts/server/utils/BackwardCompat.ts +546 -528
- package/src/ts/server/utils/validation.ts +34 -0
- package/src/ts/types.ts +295 -85
- package/.dockerignore +0 -5
- package/.editorconfig +0 -14
- package/.eslintrc.json +0 -43
- package/.github/FUNDING.yml +0 -13
- package/.github/workflows/docker-hub-publish.yml +0 -36
- package/.github/workflows/npm-publish.yml +0 -19
- package/.github/workflows/test.yml +0 -26
- package/.nvmrc +0 -1
- package/.silex/default/.silex.data.json +0 -1
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -131
- package/Dockerfile +0 -15
- package/directus.silex.js +0 -7
- package/dist/constants.js +0 -4
- package/dist/events.js +0 -5
- package/dist/page.js +0 -15
- package/dist/server/cli.js +0 -43
- package/dist/server/config.js +0 -70
- package/dist/server/express.js +0 -18
- package/dist/server/index.js +0 -58
- package/dist/types.js +0 -34
- package/jest.config.js +0 -10
- package/logos/logo_by_ceubri/silex-icon-2018@200px.png +0 -0
- package/logos/logo_by_ceubri/silex-icon-2018@4x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white-transp.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@0.5x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@0.75x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@4x.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@4x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.ai +5 -2521
- package/logos/logo_by_ceubri/silex-logo-2018.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@0.5x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@0.75x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@4x.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@4x.png +0 -0
- package/logos/silexlabs.png +0 -0
- package/src/example-client-config.js +0 -47
- package/src/plugins/AuthPlugin.js +0 -21
- package/src/plugins/Cache.js +0 -11
- package/src/plugins/DefaultBackend.js +0 -149
- package/src/plugins/ExpressPlugin.js +0 -39
- package/src/plugins/HooksPlugin.js +0 -58
- package/src/plugins/PublishPlugin.js +0 -69
- package/src/plugins/SslPlugin.js +0 -66
- package/src/plugins/StaticPlugin.js +0 -48
- package/src/plugins/WebsitePlugin.js +0 -207
- package/src/ts/client/grapesjs/publish.ts +0 -386
- package/src/ts/client/grapesjs/template.ts +0 -166
- package/src/ts/events.ts +0 -2
- package/tsconfig-server-debug.json +0 -19
- package/tsconfig-server-release.json +0 -19
- package/tsconfig.jest.json +0 -9
- package/tsconfig.json +0 -26
- package/webpack.config.js +0 -28
- package/webpack.debug.config.js +0 -8
package/src/ts/server/config.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
1
18
|
/**
|
|
2
19
|
* @fileoverview This is where the default config is defined. Also use this object as an event emitter to listen to Silex events
|
|
3
20
|
* The values can be overriden with env vars or before passing the config to Silex
|
|
@@ -8,84 +25,165 @@
|
|
|
8
25
|
*/
|
|
9
26
|
|
|
10
27
|
import { Config, Plugin } from '@silexlabs/silex-plugins'
|
|
11
|
-
import { resolve } from 'path'
|
|
28
|
+
import { join, resolve } from 'path'
|
|
12
29
|
import { CLIENT_CONFIG_FILE_NAME } from '../constants'
|
|
13
|
-
import { Router } from 'express'
|
|
30
|
+
import { Application, Request, Response, Router } from 'express'
|
|
14
31
|
import { readFile } from 'fs/promises'
|
|
15
|
-
import {
|
|
32
|
+
import { HostingConnector, StorageConnector, toConnectorEnum } from './connectors/connectors'
|
|
33
|
+
import { FsStorage } from './connectors/FsStorage'
|
|
34
|
+
import { Connector } from './connectors/connectors'
|
|
35
|
+
import { ConnectorType } from '../types'
|
|
36
|
+
import { FsHosting } from './connectors/FsHosting'
|
|
16
37
|
|
|
17
38
|
/**
|
|
18
39
|
* Config types definitions
|
|
19
40
|
*/
|
|
20
41
|
export class ServerConfig extends Config {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
public expressOptions = {
|
|
43
|
+
jsonLimit: process.env.SILEX_EXPRESS_JSON_LIMIT,
|
|
44
|
+
textLimit: process.env.SILEX_EXPRESS_TEXT_LIMIT,
|
|
45
|
+
urlencodedLimit: process.env.SILEX_EXPRESS_URLENCODED_LIMIT,
|
|
46
|
+
sessionName: process.env.SILEX_SESSION_NAME,
|
|
47
|
+
sessionSecret: process.env.SILEX_SESSION_SECRET,
|
|
48
|
+
cors: process.env.SILEX_CORS_URL,
|
|
28
49
|
}
|
|
29
|
-
|
|
50
|
+
public port = process.env.SILEX_PORT
|
|
51
|
+
public debug = process.env.SILEX_DEBUG === 'true'
|
|
52
|
+
public url = process.env.SILEX_URL?.replace(/\/$/, '') ?? `${process.env.SILEX_PROTOCOL}://${process.env.SILEX_HOST}:${process.env.SILEX_PORT}`
|
|
53
|
+
public userConfigPath: Plugin | undefined = process.env.SILEX_SERVER_CONFIG
|
|
54
|
+
public configFilePath: Plugin = resolve(__dirname, '../../../.silex.js')
|
|
55
|
+
|
|
56
|
+
// All connectors or just the storage or hosting connectors
|
|
57
|
+
getConnectors(type: ConnectorType | string | null = null): Connector[] {
|
|
58
|
+
// All connectors including storage and hosting connectors
|
|
59
|
+
if (!type) {
|
|
60
|
+
// Concat storage and hosting connectors
|
|
61
|
+
const allConnectors: Connector[] = (this.getStorageConnectors() as Connector[]).concat(this.getHostingConnectors())
|
|
62
|
+
|
|
63
|
+
// Remove duplicates (if a connector is both a storage and a hosting connector)
|
|
64
|
+
return [...new Set(allConnectors)]
|
|
65
|
+
}
|
|
30
66
|
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
const port = process.env.PORT || '6805' // 6805 is the date of sexual revolution started in paris france 8-)
|
|
34
|
-
const debug = process.env.SILEX_DEBUG === 'true'
|
|
35
|
-
const clientConfigPath = process.env.SILEX_CLIENT_CONFIG
|
|
67
|
+
// Convert to enum in case it is a string
|
|
68
|
+
const connectorType = toConnectorEnum(type.toString())
|
|
36
69
|
|
|
37
|
-
|
|
38
|
-
|
|
70
|
+
// Only one type of connector
|
|
71
|
+
switch(connectorType) {
|
|
72
|
+
case ConnectorType.HOSTING: return this.getHostingConnectors()
|
|
73
|
+
case ConnectorType.STORAGE: return this.getStorageConnectors()
|
|
74
|
+
default: throw new Error(`Unknown connector type ${type}`)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
39
77
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// Reload each time in debug mode
|
|
51
|
-
if (config.debug) {
|
|
52
|
-
console.log('[Debug mode] Reloading config file', clientConfigPath)
|
|
53
|
-
clientConfig = (await readFile(clientConfigPath)).toString()
|
|
54
|
-
}
|
|
55
|
-
// Send the config file
|
|
56
|
-
req.header('Content-Type', 'application/javascript').send(clientConfig)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
78
|
+
// Storage connectors to store the website data and assets
|
|
79
|
+
private storageConnectors: StorageConnector[] = []
|
|
80
|
+
addStorageConnector(storage: StorageConnector | StorageConnector[]) {
|
|
81
|
+
this.setStorageConnectors(this.storageConnectors.concat(storage))
|
|
82
|
+
}
|
|
83
|
+
setStorageConnectors(storageConnectors: StorageConnector[]) {
|
|
84
|
+
this.storageConnectors =storageConnectors
|
|
85
|
+
}
|
|
86
|
+
getStorageConnectors(): StorageConnector[] {
|
|
87
|
+
return this.storageConnectors
|
|
59
88
|
}
|
|
60
89
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
// Hosting connectors to publish the website online
|
|
91
|
+
private hostingConnectors: HostingConnector[] = []
|
|
92
|
+
addHostingConnector(hosting: HostingConnector | HostingConnector[]) {
|
|
93
|
+
this.setHostingConnectors(this.hostingConnectors.concat(hosting))
|
|
94
|
+
}
|
|
95
|
+
setHostingConnectors(hostings: HostingConnector[]) {
|
|
96
|
+
this.hostingConnectors = hostings
|
|
97
|
+
}
|
|
98
|
+
getHostingConnectors(): HostingConnector[] { return this.hostingConnectors }
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Add routes to serve the client config file
|
|
102
|
+
*/
|
|
103
|
+
async addRoutes(app: Application) {
|
|
104
|
+
const path = process.env.SILEX_CLIENT_CONFIG
|
|
105
|
+
if (path) {
|
|
106
|
+
console.info(`> Serving client side config ${path} at ${CLIENT_CONFIG_FILE_NAME}`)
|
|
107
|
+
try {
|
|
108
|
+
// Load the client config file
|
|
109
|
+
let clientConfig = (await readFile(path as string)).toString()
|
|
110
|
+
// Serve the config file
|
|
111
|
+
app.get(`/${CLIENT_CONFIG_FILE_NAME}`, async (req: Request, res: Response) => {
|
|
112
|
+
// Reload each time in debug mode
|
|
113
|
+
if (this.debug) {
|
|
114
|
+
console.info('[Debug mode] Reloading config file', path)
|
|
115
|
+
clientConfig = (await readFile(path)).toString()
|
|
116
|
+
}
|
|
117
|
+
// Send the config file
|
|
118
|
+
res
|
|
119
|
+
.contentType('application/javascript')
|
|
120
|
+
.send(clientConfig)
|
|
121
|
+
})
|
|
122
|
+
} catch (e) {
|
|
123
|
+
console.error(`Error loading client config file ${path}`, e)
|
|
124
|
+
throw new Error(`Error loading client config file ${path}: ${e.message}`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Load config files
|
|
131
|
+
* This is the main config file and the user config file
|
|
132
|
+
*/
|
|
133
|
+
async loadConfigFiles() {
|
|
134
|
+
// Load the user config file
|
|
135
|
+
await this.loadUserConfig()
|
|
136
|
+
// Load the main config file
|
|
137
|
+
await this.loadSilexConfig()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Load user config file
|
|
142
|
+
* This is the config file passed as env var CONFIG
|
|
143
|
+
*/
|
|
144
|
+
async loadUserConfig() {
|
|
145
|
+
if (this.userConfigPath) {
|
|
146
|
+
console.info('> Loading user config', this.userConfigPath)
|
|
147
|
+
try {
|
|
148
|
+
// Initiate the process with the config file which is just another plugin
|
|
149
|
+
await this.addPlugin(this.userConfigPath, {})
|
|
150
|
+
} catch (e) {
|
|
151
|
+
throw new Error(`\nUser config file ${this.userConfigPath} error:\n\n\t${e.message}\n\n`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Load .silex.js in the root folder
|
|
158
|
+
* This is the main config file
|
|
159
|
+
*/
|
|
160
|
+
async loadSilexConfig() {
|
|
161
|
+
console.info('> Loading config', this.configFilePath)
|
|
67
162
|
try {
|
|
68
163
|
// Initiate the process with the config file which is just another plugin
|
|
69
|
-
await
|
|
70
|
-
} catch
|
|
71
|
-
|
|
164
|
+
await this.addPlugin(this.configFilePath, {})
|
|
165
|
+
} catch(e) {
|
|
166
|
+
// Check if the error is about the config file not found and not another module not found in the config file
|
|
167
|
+
if(e.code === 'MODULE_NOT_FOUND' && (!e.requireStack || !e.requireStack.find(path => path === this.configFilePath))) {
|
|
168
|
+
console.info('> /!\\ Config file not found', this.configFilePath)
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error(`Error in config file ${this.configFilePath}: ${e.message}`)
|
|
171
|
+
}
|
|
72
172
|
}
|
|
73
173
|
}
|
|
74
174
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
175
|
+
async initDefaultConnectors() {
|
|
176
|
+
// Add default storage connectors
|
|
177
|
+
if (!this.storageConnectors.length) {
|
|
178
|
+
this.addStorageConnector(new FsStorage(null, {
|
|
179
|
+
path: process.env.SILEX_FS_ROOT || join(process.cwd(), '/silex/storage'),
|
|
180
|
+
}))
|
|
181
|
+
}
|
|
182
|
+
// Add default hosting connectors
|
|
183
|
+
if (!this.hostingConnectors.length) {
|
|
184
|
+
this.addHostingConnector(new FsHosting(null, {
|
|
185
|
+
path: process.env.SILEX_FS_HOSTING_ROOT || join(process.cwd(), '/silex/hosting'),
|
|
186
|
+
}))
|
|
86
187
|
}
|
|
87
188
|
}
|
|
88
|
-
|
|
89
|
-
// Return the config file
|
|
90
|
-
return config
|
|
91
189
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs/promises'
|
|
19
|
+
import { ConnectorFile, StorageConnector, HostingConnector, StatusCallback, ConnectorSession, contentToString, toConnectorData, ConnectorFileContent} from './connectors'
|
|
20
|
+
import { join } from 'path'
|
|
21
|
+
import { FsStorage } from './FsStorage'
|
|
22
|
+
import { ConnectorType, JobData, JobStatus, PublicationJobData, WebsiteId } from '../../types'
|
|
23
|
+
import { JobManager } from '../jobs'
|
|
24
|
+
|
|
25
|
+
type FsSession = ConnectorSession
|
|
26
|
+
|
|
27
|
+
export class FsHosting extends FsStorage implements HostingConnector<FsSession> {
|
|
28
|
+
connectorId = 'fs-hosting'
|
|
29
|
+
displayName = 'File system hosting'
|
|
30
|
+
connectorType = ConnectorType.HOSTING
|
|
31
|
+
|
|
32
|
+
protected async initFs() {
|
|
33
|
+
const stat = await fs.stat(this.options.path).catch(() => null)
|
|
34
|
+
if (!stat) {
|
|
35
|
+
await fs.mkdir(join(this.options.path, 'assets'), { recursive: true })
|
|
36
|
+
await fs.mkdir(join(this.options.path, 'css'), { recursive: true })
|
|
37
|
+
console.info(`> [FsHosting] Created folders assets/ and css/ in ${this.options.path}`)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async publish(session: FsSession, id: WebsiteId, files: ConnectorFile[], {startJob, jobSuccess, jobError}: JobManager): Promise<JobData> {
|
|
42
|
+
const job = startJob(`Publishing to ${this.displayName}`) as PublicationJobData
|
|
43
|
+
job.logs = [[`Publishing to ${this.displayName}`]]
|
|
44
|
+
job.errors = [[]]
|
|
45
|
+
// Call write without id or folder so that it goes in / (path will be modified by publication transformers)
|
|
46
|
+
await this.write(session, '', files, '', async ({status, message}) => {
|
|
47
|
+
// Update the job status
|
|
48
|
+
job.status = status
|
|
49
|
+
job.message = message
|
|
50
|
+
job.logs[0].push(message)
|
|
51
|
+
if(status === JobStatus.SUCCESS) {
|
|
52
|
+
jobSuccess(job.jobId, message)
|
|
53
|
+
} else if(status === JobStatus.ERROR) {
|
|
54
|
+
job.errors[0].push(message)
|
|
55
|
+
jobError(job.jobId, message)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
return job
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async getUrl(session: FsSession, id: WebsiteId): Promise<string> {
|
|
62
|
+
const filePath = join(this.options.path, id, 'index.html')
|
|
63
|
+
const fileUrl = new URL(filePath, 'file://')
|
|
64
|
+
return fileUrl.toString()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { expect, beforeEach, afterAll, it, describe } from '@jest/globals'
|
|
2
|
+
import { ServerConfig } from '../config'
|
|
3
|
+
import { FsStorage } from './FsStorage'
|
|
4
|
+
import { readFileSync, rmdirSync, statSync } from 'fs'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
|
|
7
|
+
const storageRootPath = '/tmp/silex-tests'
|
|
8
|
+
const assetsFolder = 'assets'
|
|
9
|
+
const dummySession = {}
|
|
10
|
+
const dummyId = 'dummy id'
|
|
11
|
+
const dummyWebsite = {
|
|
12
|
+
pages: [],
|
|
13
|
+
assets: [],
|
|
14
|
+
styles: [],
|
|
15
|
+
settings: {},
|
|
16
|
+
fonts: [],
|
|
17
|
+
symbols: [],
|
|
18
|
+
publication: {},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
afterAll(() => {
|
|
25
|
+
rmdirSync(storageRootPath, { recursive: true })
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
async function sleep(ms: number) {
|
|
29
|
+
return new Promise(resolve => setTimeout(resolve, ms))
|
|
30
|
+
}
|
|
31
|
+
describe('FsStorage website', () => {
|
|
32
|
+
it('should create the root folder', async () => {
|
|
33
|
+
expect(() => statSync(storageRootPath)).toThrow()
|
|
34
|
+
const connector = new FsStorage({} as ServerConfig, {
|
|
35
|
+
path: storageRootPath,
|
|
36
|
+
assetsFolder,
|
|
37
|
+
})
|
|
38
|
+
await sleep(100)
|
|
39
|
+
expect(() => statSync(storageRootPath)).not.toThrow()
|
|
40
|
+
})
|
|
41
|
+
it('should create a new website', async () => {
|
|
42
|
+
const connector = new FsStorage({} as ServerConfig, {
|
|
43
|
+
path: storageRootPath,
|
|
44
|
+
assetsFolder,
|
|
45
|
+
})
|
|
46
|
+
const id = await connector.createWebsite(dummySession, { name: 'dummy name', connectorUserSettings: {} })
|
|
47
|
+
expect(id).toBeDefined()
|
|
48
|
+
expect(() => statSync(join(storageRootPath, id, 'website.json'))).not.toThrow()
|
|
49
|
+
expect(readFileSync(join(storageRootPath, id, 'website.json'), 'utf8')).toBe(JSON.stringify({}))
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs/promises'
|
|
19
|
+
import { createWriteStream } from 'fs'
|
|
20
|
+
import { ConnectorFile, StorageConnector, StatusCallback, ConnectorSession, toConnectorData, ConnectorFileContent} from './connectors'
|
|
21
|
+
import { dirname, join } from 'path'
|
|
22
|
+
import { ConnectorUser, WebsiteMeta, JobStatus, WebsiteId, ConnectorType, WebsiteMetaFileContent, WebsiteData, defaultWebsiteData, ConnectorOptions } from '../../types'
|
|
23
|
+
import { userInfo } from 'os'
|
|
24
|
+
import { requiredParam } from '../utils/validation'
|
|
25
|
+
import { ServerConfig } from '../config'
|
|
26
|
+
import { DEFAULT_WEBSITE_ID, WEBSITE_DATA_FILE, WEBSITE_META_DATA_FILE } from '../../constants'
|
|
27
|
+
import { Readable } from 'stream'
|
|
28
|
+
import { v4 as uuid } from 'uuid'
|
|
29
|
+
import { fileURLToPath } from 'url'
|
|
30
|
+
|
|
31
|
+
// Variables needed for jest tests
|
|
32
|
+
if(!globalThis.__dirname) {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
globalThis.__dirname = dirname(process.cwd() + '/src/ts/server/connectors/FsStorage.ts')
|
|
35
|
+
console.info('Redefining __dirname', globalThis.__dirname)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Copy a folder recursively
|
|
39
|
+
async function copyDir(src, dest) {
|
|
40
|
+
await fs.mkdir(dest, { recursive: true })
|
|
41
|
+
const entries = await fs.readdir(src, { withFileTypes: true })
|
|
42
|
+
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const srcPath = join(src, entry.name)
|
|
45
|
+
const destPath = join(dest, entry.name)
|
|
46
|
+
|
|
47
|
+
entry.isDirectory() ?
|
|
48
|
+
await copyDir(srcPath, destPath) :
|
|
49
|
+
await fs.copyFile(srcPath, destPath)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
type FsSession = ConnectorSession
|
|
55
|
+
|
|
56
|
+
const USER_ICON = 'data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' height=\'1em\' viewBox=\'0 0 448 512\'%3E%3Cpath d=\'M304 128a80 80 0 1 0 -160 0 80 80 0 1 0 160 0zM96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM49.3 464H398.7c-8.9-63.3-63.3-112-129-112H178.3c-65.7 0-120.1 48.7-129 112zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3z\'/%3E%3C/svg%3E'
|
|
57
|
+
const FILE_ICON = '/assets/laptop.png'
|
|
58
|
+
|
|
59
|
+
interface FsOptions {
|
|
60
|
+
path: string
|
|
61
|
+
assetsFolder: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class FsStorage implements StorageConnector<FsSession> {
|
|
65
|
+
connectorId = 'fs-storage'
|
|
66
|
+
displayName = 'File system storage'
|
|
67
|
+
icon = FILE_ICON
|
|
68
|
+
disableLogout = true
|
|
69
|
+
options: FsOptions
|
|
70
|
+
connectorType = ConnectorType.STORAGE
|
|
71
|
+
color = '#ffffff'
|
|
72
|
+
background = '#006400'
|
|
73
|
+
|
|
74
|
+
constructor(config: ServerConfig | null, opts: Partial<FsOptions>) {
|
|
75
|
+
this.options = {
|
|
76
|
+
path: join(__dirname, '..', '..', '..', '..', 'data'),
|
|
77
|
+
assetsFolder: '/assets',
|
|
78
|
+
...opts,
|
|
79
|
+
}
|
|
80
|
+
this.initFs()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
protected async initFs() {
|
|
84
|
+
const stat = await fs.stat(this.options.path).catch(() => null)
|
|
85
|
+
if (!stat) {
|
|
86
|
+
// create data folder with a default website
|
|
87
|
+
const id = DEFAULT_WEBSITE_ID
|
|
88
|
+
await fs.mkdir(join(this.options.path, id, this.options.assetsFolder), { recursive: true })
|
|
89
|
+
await this.setWebsiteMeta({}, id, { name: 'Default website', connectorUserSettings: {} })
|
|
90
|
+
await this.updateWebsite({}, id, defaultWebsiteData)
|
|
91
|
+
console.info(`> [FsStorage] Created ${id} in ${this.options.path}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ********************
|
|
96
|
+
// Job utils methods
|
|
97
|
+
// ********************
|
|
98
|
+
private updateStatus(filesStatuses, status, statusCbk) {
|
|
99
|
+
statusCbk && statusCbk({
|
|
100
|
+
message: `<p>Writing files:<ul><li>${filesStatuses.map(({file, message}) => `${file.path}: ${message}`).join('</li><li>')}</li></ul></p>`,
|
|
101
|
+
status,
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private initStatus(files) {
|
|
106
|
+
return files.map(file => ({
|
|
107
|
+
file,
|
|
108
|
+
message: 'Waiting',
|
|
109
|
+
status: JobStatus.IN_PROGRESS,
|
|
110
|
+
}))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ********************
|
|
114
|
+
// Connector interface
|
|
115
|
+
// ********************
|
|
116
|
+
getOptions(formData: object): ConnectorOptions {
|
|
117
|
+
return {}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async getOAuthUrl(session: FsSession): Promise<null> { return null }
|
|
121
|
+
|
|
122
|
+
async getLoginForm(session: FsSession, redirectTo: string): Promise<string | null> {
|
|
123
|
+
return null
|
|
124
|
+
}
|
|
125
|
+
async getSettingsForm(session: FsSession, redirectTo: string): Promise<string | null> {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async isLoggedIn(session: FsSession): Promise<boolean> {
|
|
130
|
+
return true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async setToken(session: FsSession, query: object): Promise<void> {}
|
|
134
|
+
|
|
135
|
+
async logout(session: FsSession): Promise<void> {}
|
|
136
|
+
|
|
137
|
+
async getUser(session: FsSession): Promise<ConnectorUser> {
|
|
138
|
+
const { username, } = userInfo()
|
|
139
|
+
return {
|
|
140
|
+
name: username,
|
|
141
|
+
picture: USER_ICON,
|
|
142
|
+
storage: await toConnectorData(session, this),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async setWebsiteMeta(session: any, id: string, data: WebsiteMetaFileContent): Promise<void> {
|
|
147
|
+
const websiteId = requiredParam<WebsiteId>(id, 'website id')
|
|
148
|
+
const content = JSON.stringify(data)
|
|
149
|
+
const path = join(this.options.path, id, WEBSITE_META_DATA_FILE)
|
|
150
|
+
await fs.writeFile(path, content)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async getWebsiteMeta(session: FsSession, id: WebsiteId): Promise<WebsiteMeta> {
|
|
154
|
+
const websiteId = requiredParam<WebsiteId>(id, 'website id')
|
|
155
|
+
// Get stats for website folder
|
|
156
|
+
const fileStat = await fs.stat(join(this.options.path, websiteId))
|
|
157
|
+
const path = join(this.options.path, websiteId, WEBSITE_META_DATA_FILE)
|
|
158
|
+
// Get meta file
|
|
159
|
+
const content = await fs.readFile(path)
|
|
160
|
+
const meta = await JSON.parse(content.toString())
|
|
161
|
+
// Return all meta
|
|
162
|
+
return {
|
|
163
|
+
websiteId,
|
|
164
|
+
name: meta.name,
|
|
165
|
+
imageUrl: meta.imageUrl,
|
|
166
|
+
connectorUserSettings: meta.connectorUserSettings,
|
|
167
|
+
createdAt: fileStat.birthtime,
|
|
168
|
+
updatedAt: fileStat.mtime,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ********************
|
|
173
|
+
// Storage interface
|
|
174
|
+
// ********************
|
|
175
|
+
async createWebsite(session: FsSession, meta: WebsiteMetaFileContent): Promise<WebsiteId> {
|
|
176
|
+
const id = uuid()
|
|
177
|
+
await fs.mkdir(join(this.options.path, id, this.options.assetsFolder), { recursive: true })
|
|
178
|
+
await this.setWebsiteMeta(session, id, meta)
|
|
179
|
+
await this.updateWebsite(session, id, defaultWebsiteData)
|
|
180
|
+
return id
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async readWebsite(session: FsSession, websiteId: WebsiteId): Promise<WebsiteData> {
|
|
184
|
+
const id = requiredParam<WebsiteId>(websiteId, 'website id')
|
|
185
|
+
const path = join(this.options.path, id, WEBSITE_DATA_FILE)
|
|
186
|
+
const content = await fs.readFile(path)
|
|
187
|
+
return JSON.parse(content.toString())
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async updateWebsite(session: FsSession, websiteId: WebsiteId, data: WebsiteData): Promise<void> {
|
|
191
|
+
const id = requiredParam<WebsiteId>(websiteId, 'website id')
|
|
192
|
+
const path = join(this.options.path, id, WEBSITE_DATA_FILE)
|
|
193
|
+
await fs.writeFile(path, JSON.stringify(data))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async deleteWebsite(session: FsSession, websiteId: WebsiteId): Promise<void> {
|
|
197
|
+
const id = requiredParam<WebsiteId>(websiteId, 'website id')
|
|
198
|
+
const path = join(this.options.path, id)
|
|
199
|
+
return fs.rmdir(path, { recursive: true })
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async duplicateWebsite(session: FsSession, websiteId: WebsiteId): Promise<void> {
|
|
203
|
+
const newWebsiteId = uuid()
|
|
204
|
+
const from = join(this.options.path, websiteId)
|
|
205
|
+
const to = join(this.options.path, newWebsiteId)
|
|
206
|
+
await copyDir(from, to)
|
|
207
|
+
const meta = await this.getWebsiteMeta(session, websiteId)
|
|
208
|
+
await this.setWebsiteMeta(session, newWebsiteId, {
|
|
209
|
+
...meta,
|
|
210
|
+
name: `${meta.name} copy`,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async listWebsites(session: any): Promise<WebsiteMeta[]> {
|
|
215
|
+
const list = await fs.readdir(this.options.path)
|
|
216
|
+
return Promise.all(list.map(async fileName => {
|
|
217
|
+
const websiteId = fileName as WebsiteId
|
|
218
|
+
return this.getWebsiteMeta(session, websiteId)
|
|
219
|
+
}))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async getAsset(session: FsSession, id: WebsiteId, path: string): Promise<ConnectorFile> {
|
|
223
|
+
const fullPath = join(this.options.path, id, this.options.assetsFolder, path)
|
|
224
|
+
const content = await fs.readFile(fullPath)
|
|
225
|
+
return { path, content }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async writeAssets(session: FsSession, id: WebsiteId, files: ConnectorFile[], statusCbk?: StatusCallback): Promise<void> {
|
|
229
|
+
return this.write(session, id, files, this.options.assetsFolder, statusCbk)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async write(session: FsSession, id: WebsiteId, files: ConnectorFile[], assetsFolder: string, statusCbk?: StatusCallback): Promise<void> {
|
|
233
|
+
const filesStatuses = this.initStatus(files)
|
|
234
|
+
let error: Error | null = null
|
|
235
|
+
for (const fileStatus of filesStatuses) {
|
|
236
|
+
const {file} = fileStatus
|
|
237
|
+
const path = join(this.options.path, id, assetsFolder, file.path)
|
|
238
|
+
if (typeof file.content === 'string' || Buffer.isBuffer(file.content)) {
|
|
239
|
+
fileStatus.message = 'Writing'
|
|
240
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
241
|
+
try {
|
|
242
|
+
await fs.writeFile(path, file.content)
|
|
243
|
+
} catch(err) {
|
|
244
|
+
fileStatus.message = `Error (${err})`
|
|
245
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
246
|
+
error = err
|
|
247
|
+
continue
|
|
248
|
+
}
|
|
249
|
+
fileStatus.message = 'Success'
|
|
250
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
251
|
+
} else if (file.content instanceof Readable) {
|
|
252
|
+
fileStatus.message = 'Writing'
|
|
253
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
254
|
+
const writeStream = createWriteStream(path)
|
|
255
|
+
file.content.pipe(writeStream)
|
|
256
|
+
await new Promise((resolve) => {
|
|
257
|
+
writeStream.on('finish', () => {
|
|
258
|
+
fileStatus.message = 'Success'
|
|
259
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
260
|
+
resolve(file)
|
|
261
|
+
})
|
|
262
|
+
writeStream.on('error', err => {
|
|
263
|
+
console.error('writeStream error', err)
|
|
264
|
+
fileStatus.message = `Error (${err})`
|
|
265
|
+
this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
|
|
266
|
+
error = err
|
|
267
|
+
resolve(file)
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
} else {
|
|
271
|
+
console.error('Invalid file content', typeof file.content)
|
|
272
|
+
throw new Error('Invalid file content: ' + typeof file.content)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
this.updateStatus(filesStatuses, error ? JobStatus.ERROR : JobStatus.SUCCESS, statusCbk)
|
|
276
|
+
if(error) throw error
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async deleteAssets(session: FsSession, id: WebsiteId, paths: string[]): Promise<void> {
|
|
280
|
+
for (const path of paths) {
|
|
281
|
+
await fs.unlink(join(this.options.path, id, path))
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async readAsset(session: object, websiteId: string, fileName: string): Promise<ConnectorFileContent> {
|
|
286
|
+
const id = requiredParam<WebsiteId>(websiteId, 'website id')
|
|
287
|
+
const path = join(this.options.path, id, this.options.assetsFolder, fileName)
|
|
288
|
+
return await fs.readFile(path)
|
|
289
|
+
}
|
|
290
|
+
}
|