diff --git a/.github/workflows/gitops-dev.yml b/.github/workflows/gitops-dev.yml new file mode 100644 index 000000000..af10088ce --- /dev/null +++ b/.github/workflows/gitops-dev.yml @@ -0,0 +1,98 @@ +name: GitopsDev + +# Run this workflow every time a new commit pushed to your repository +on: + push: + branches: + - master + - development + - feature/* + - release/* + - release + +jobs: + gitops: + environment: gitops_dev + env: + HELM_REPO_NAME: openstad-kubernetes + HELM_CHART_FOLDER: k8s/openstad + GIT_USER_EMAIL: github@ci.push + GIT_USER_NAME: GitHub + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + HELM_REPO: ${{ secrets.HELM_REPO }} + HELM_REPO_WITH_TOKEN: ${{ secrets.HELM_REPO_WITH_TOKEN }} + GITOPS_RELEASE_BRANCH: ${{ secrets.GITOPS_RELEASE_BRANCH }} + FRONTED_PORT: 4444 + FRONTEND_MONGO_SCHEME: mongodb://mongo + FRONTEND_MONGO_DB_HOST: mongo + FRONTEND_MONGO_PORT: 27017 + FRONTEND_MINIFY_JS: ON + COOKIE_SECURE_OFF: yes + API: http://localhost:8111 + IMAGE_API_URL: http://localhost:3333 + IMAGE_API_ACCESS_TOKEN: xxxx + SITE_API_KEY: xxxx + DEFAULT_DB: localhost2 + DEFAULT_HOST: localhost:4444 + APP_URL: http://localhost:4444 + APOS_BUNDLE: assets + APOS_MINIFY: 1 + NODE_ENV: production + BRANCH_REF: ${{ github.ref }} + GITOPS_VALUES_FILE: k8s/openstad/environments/dev.values.yaml + + name: gitops commit + runs-on: ubuntu-latest + + services: + docker: + image: docker + mongodb: + image: mongo:3.4.23 + ports: + - 27017:27017 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + + - name: Set environment to acc + id: acc_values_file + shell: bash + if: contains(github.ref, 'release') + run: echo "GITOPS_VALUES_FILE=k8s/openstad/environments/acc.values.yaml" >> $GITHUB_ENV + + - name: Set environment to production + id: prod_values_file + shell: bash + if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' + run: echo "GITOPS_VALUES_FILE=k8s/openstad/environments/prod.values.yaml" >> $GITHUB_ENV + + - name: Set commit SHA & current branch + id: vars + shell: bash + run: | + echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + echo "::set-output name=current_branch::$(git branch --show-current | sed "s/\//-/g")" + + - name: Install yq + run: sudo snap install yq --channel=v3/stable + + + - name: Run build script + run: | + sudo chmod a+x ./build.sh + ./build.sh + shell: bash + env: + IMAGE_TAG: ${{ secrets.DOCKER_PUBLIC_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.vars.outputs.current_branch }}-${{ steps.vars.outputs.sha_short }}-${{ github.run_id}} + + - name: Run docker push script + run: | + sudo chmod a+x ./gitops_push + ./gitops_push + shell: bash + env: + IMAGE_TAG: ${{ secrets.DOCKER_PUBLIC_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.vars.outputs.current_branch }}-${{ steps.vars.outputs.sha_short }}-${{ github.run_id}} diff --git a/.travis.yml b/.travis.yml index 706a16534..0b773ac84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,9 @@ env: - GITOPS_ACC_VALUES_FILE=${GITOPS_ACC_VALUES_FILE:-k8s/openstad/environments/acc.values.yaml} - GITOPS_PROD_VALUES_FILE=${GITOPS_PROD_VALUES_FILE:-k8s/openstad/environments/prod.values.yaml} + - GIT_USER_EMAIL="travis@travis-ci.org" + - GIT_USER_NAME="Travis CI" + # Kube deploy variables - K8S_DEPLOYMENT_NAME=openstad-frontend - K8S_NAMESPACE=openstad diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af3d1538..30758b4f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased +* Make image size configurable for the image widget +* Fix HTML injection in search form in the resource overview widget +* Add a new text style to select in the rich text editor. +* Make autoCenter configurable in idea-map-widgets + ## 1.0.0 * Add submission to resource form with configurable confirmation settings * Update ideas-on-map config to work with react-leaflet diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..cb138cb12 --- /dev/null +++ b/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +sleep 15 +mongo default --eval 'db.createUser({user:"ci",pwd:"test",roles:["readWrite"]});' +npm install --production +npm run test -- --coverage +mkdir assets +NODE_ENV=production APOS_MINIFY=1 APOS_WORKFLOW=ON APOS_BUNDLE=assets node apostrophe.js apostrophe:generation --create-bundle assets +docker build -t ${IMAGE_TAG} . diff --git a/gitops_push b/gitops_push index 1711ef4cd..76242404f 100644 --- a/gitops_push +++ b/gitops_push @@ -6,8 +6,8 @@ echo "DOCKER PUSH TAG" echo ${IMAGE_TAG} docker push ${IMAGE_TAG} -git config --global user.email "travis@travis-ci.org" -git config --global user.name "Travis CI" +git config --global user.email ${GIT_USER_EMAIL} +git config --global user.name ${GIT_USER_NAME} git clone ${HELM_REPO} && cd ${HELM_REPO_NAME} && \ diff --git a/packages/cms/config/siteConfig.js b/packages/cms/config/siteConfig.js index 51a929bf7..db4645ca9 100644 --- a/packages/cms/config/siteConfig.js +++ b/packages/cms/config/siteConfig.js @@ -63,7 +63,7 @@ module.exports = { httpOnly: true, secure: process.env.COOKIE_SECURE_OFF === 'yes' ? false : true, // Default login lifetime between requests is one day - maxAge: process.env.COOKIE_MAX_AGE || 86400000 + maxAge: parseInt(process.env.COOKIE_MAX_AGE) && ! isNaN(parseInt(process.env.COOKIE_MAX_AGE)) ? parseInt(process.env.COOKIE_MAX_AGE) : 86400000 } }, csrf: { diff --git a/packages/cms/lib/modules/choices-guide-result-widgets/index.js b/packages/cms/lib/modules/choices-guide-result-widgets/index.js index 43ed8961b..3e828bf6f 100755 --- a/packages/cms/lib/modules/choices-guide-result-widgets/index.js +++ b/packages/cms/lib/modules/choices-guide-result-widgets/index.js @@ -35,18 +35,28 @@ module.exports = { const superLoad = self.load; self.load = function(req, widgets, next) { + let apiUrl = self.apos.settings.getOption(req, 'apiUrl') widgets.forEach((widget) => { - let apiUrl = self.apos.settings.getOption(req, 'apiUrl') let config = createConfig({ widget: widget, data: req.data, + jwt: req.session.jwt, + apiUrl: apiUrl, logoutUrl: apiUrl + '/oauth/logout', + loginUrl: req.data.siteUrl + '/oauth/login?returnTo=' + encodeURIComponent(req.url) }); widget.config = config; widget.divId = widget.config.divId; - }); + + widget.openstadComponentsCdn = (req && req.data && req.data.global && req.data.global.openstadComponentsUrl) || self.apos.settings.getOption(req, 'siteConfig').openstadComponentsCdn; + + const containerId = self.apos.utils.generateId(); + widget.containerId = containerId; + widget.cssHelperClassesString = widget.cssHelperClasses ? widget.cssHelperClasses.join(' ') : ''; + widget.formattedContainerStyles = styleSchema.format(containerId, widget.containerStyles); + }); return superLoad(req, widgets, next); next(); diff --git a/packages/cms/lib/modules/choices-guide-result-widgets/lib/create-config.js b/packages/cms/lib/modules/choices-guide-result-widgets/lib/create-config.js index d99d79bd4..36acd0b1f 100755 --- a/packages/cms/lib/modules/choices-guide-result-widgets/lib/create-config.js +++ b/packages/cms/lib/modules/choices-guide-result-widgets/lib/create-config.js @@ -1,4 +1,4 @@ -module.exports = function createConfig({ widget, data, logoutUrl }) { +module.exports = function createConfig({ widget, data, logoutUrl, loginUrl, jwt, apiUrl }) { let requireLoginSettings; requireLoginSettings = {}; @@ -16,6 +16,16 @@ module.exports = function createConfig({ widget, data, logoutUrl }) { divId: 'ocs-choices-guide-result-' + parseInt(Math.random() * 1000000).toString(), + siteId: data.global.siteId, + api: { + url: apiUrl, + headers: jwt ? { 'X-Authorization': 'Bearer ' + jwt } : {}, + isUserLoggedIn: data.loggedIn, + }, + user: { + role: data.openstadUser && data.openstadUser.role, + displayName: data.openstadUser && data.openstadUser.displayName, + }, choicesGuideId: widget.choicesGuideId, questionGroupId: widget.questionGroupId, startWithAllQuestionsAnswered: widget.startWithAllQuestionsAnswered, @@ -30,6 +40,7 @@ module.exports = function createConfig({ widget, data, logoutUrl }) { maxLabel: widget.choicesMaxLabel, withPercentage: widget.choicesWithPercentage, }, + loginUrl, logoutUrl, moreInfoUrl: widget.moreInfoUrl && data.siteUrl + widget.moreInfoUrl, moreInfoLabel: widget.moreInfoLabel, diff --git a/packages/cms/lib/modules/choices-guide-widgets/index.js b/packages/cms/lib/modules/choices-guide-widgets/index.js index 1e05fe2e3..0633cb086 100644 --- a/packages/cms/lib/modules/choices-guide-widgets/index.js +++ b/packages/cms/lib/modules/choices-guide-widgets/index.js @@ -41,10 +41,19 @@ module.exports = { let config = createConfig({ widget: widget, data: req.data, + jwt: req.session.jwt, + apiUrl: self.apos.settings.getOption(req, 'apiUrl') }); widget.config = config; widget.divId = widget.config.divId; - }); + + widget.openstadComponentsCdn = (req && req.data && req.data.global && req.data.global.openstadComponentsUrl) || self.apos.settings.getOption(req, 'siteConfig').openstadComponentsCdn; + + const containerId = self.apos.utils.generateId(); + widget.containerId = containerId; + widget.cssHelperClassesString = widget.cssHelperClasses ? widget.cssHelperClasses.join(' ') : ''; + widget.formattedContainerStyles = styleSchema.format(containerId, widget.containerStyles); + }); return superLoad(req, widgets, next); next(); diff --git a/packages/cms/lib/modules/choices-guide-widgets/lib/create-config.js b/packages/cms/lib/modules/choices-guide-widgets/lib/create-config.js index 943e7e8bc..1de75a31a 100755 --- a/packages/cms/lib/modules/choices-guide-widgets/lib/create-config.js +++ b/packages/cms/lib/modules/choices-guide-widgets/lib/create-config.js @@ -1,9 +1,18 @@ -module.exports = function createConfig({ widget, data }) { +module.exports = function createConfig({ widget, data, jwt, apiUrl }) { let config = { divId: 'ocs-choices-guide-' + parseInt(Math.random() * 1000000).toString(), - + siteId: data.global.siteId, + api: { + url: apiUrl, + headers: jwt ? { 'X-Authorization': 'Bearer ' + jwt } : {}, + isUserLoggedIn: data.loggedIn, + }, + user: { + role: data.openstadUser && data.openstadUser.role, + displayName: data.openstadUser && data.openstadUser.displayName, + }, choicesGuideId: widget.choicesGuideId, noOfQuestionsToShow: widget.noOfQuestionsToShow, @@ -24,7 +33,13 @@ module.exports = function createConfig({ widget, data }) { beforeUrl: widget.beforeUrl && data.siteUrl + widget.beforeUrl, afterUrl: widget.afterUrl && data.siteUrl + widget.afterUrl, image: { + server: { + process: '/image', + fetch: '/image', + srcExtension: '/:/rs=w:[[width]],h:[[height]];cp=w:[[width]],h:[[height]]', + }, aspectRatio: widget.imageAspectRatio || '16x9', + allowMultipleImages: false, }, } diff --git a/packages/cms/lib/modules/ideas-on-map-widgets/index.js b/packages/cms/lib/modules/ideas-on-map-widgets/index.js index f6b5c3f85..cf7523c4c 100755 --- a/packages/cms/lib/modules/ideas-on-map-widgets/index.js +++ b/packages/cms/lib/modules/ideas-on-map-widgets/index.js @@ -21,6 +21,8 @@ module.exports = { const superLoad = self.load; self.load = function(req, widgets, next) { + const siteUrl = self.apos.settings.getOption(req, 'siteUrl'); + let imageProxy = siteUrl + '/image'; widgets.forEach((widget) => { @@ -28,9 +30,21 @@ module.exports = { widget: widget, data: req.data, apos: self.apos, + jwt: req.session.jwt, + apiUrl: self.apos.settings.getOption(req, 'apiUrl'), + imageProxy, + loginUrl: req.data.siteUrl + '/oauth/login?{returnTo}' }); widget.config = config; widget.divId = widget.config.divId; + + widget.openstadComponentsCdn = (req && req.data && req.data.global && req.data.global.openstadComponentsUrl) || self.apos.settings.getOption(req, 'siteConfig').openstadComponentsCdn; + + const containerId = self.apos.utils.generateId(); + widget.containerId = containerId; + widget.cssHelperClassesString = widget.cssHelperClasses ? widget.cssHelperClasses.join(' ') : ''; + widget.formattedContainerStyles = styleSchema.format(containerId, widget.containerStyles); + }); return superLoad(req, widgets, next); diff --git a/packages/cms/lib/modules/ideas-on-map-widgets/lib/create-config.js b/packages/cms/lib/modules/ideas-on-map-widgets/lib/create-config.js index b59aa17b6..311a25a20 100755 --- a/packages/cms/lib/modules/ideas-on-map-widgets/lib/create-config.js +++ b/packages/cms/lib/modules/ideas-on-map-widgets/lib/create-config.js @@ -1,7 +1,7 @@ const sortingOptions = require('../../../../config/sorting.js').ideasOnMapOptions; const ideaForm = require('./idea-form'); -module.exports = function createConfig({ widget, data, apos }) { +module.exports = function createConfig({ widget, data, apos, jwt, apiUrl, loginUrl, imageProxy }) { let contentConfig = { ignoreReactionsForIdeaIds: widget.ignoreReactionsForIdeaIds, @@ -43,7 +43,16 @@ module.exports = function createConfig({ widget, data, apos }) { let config = { divId: 'ocs-component-ideas-on-map-' + parseInt(Math.random() * 1000000).toString(), - + siteId: data.global.siteId, + api: { + url: apiUrl, + headers: jwt ? { 'X-Authorization': 'Bearer ' + jwt } : [], + isUserLoggedIn: data.loggedIn, + }, + user: { + role: data.openstadUser && data.openstadUser.role, + displayName: data.openstadUser && data.openstadUser.displayName, + }, display: { type: widget.displayType, width: widget.displayWidth, @@ -53,7 +62,8 @@ module.exports = function createConfig({ widget, data, apos }) { canSelectLocation: widget.canSelectLocation, onMarkerClickAction: widget.onMarkerClickAction, startWithListOpenOnMobile: widget.startWithListOpenOnMobile, - + + loginUrl, linkToCompleteUrl: widget.linkToCompleteUrl && data.siteUrl + widget.linkToCompleteUrl, linkToUserPageUrl: widget.linkToUserPageUrl && data.siteUrl + widget.linkToUserPageUrl, @@ -84,8 +94,13 @@ module.exports = function createConfig({ widget, data, apos }) { showSortButton: widget.selectedSorting && widget.selectedSorting.length ? true : false, defaultValue: widget.defaultSorting, }, - + image: { + server: { + process: imageProxy, + fetch: imageProxy, + srcExtension: '/:/rs=w:[[width]],h:[[height]];cp=w:[[width]],h:[[height]]', + }, aspectRatio: widget.imageAspectRatio || '16x9', allowMultipleImages, placeholderImageSrc, diff --git a/packages/cms/lib/modules/image-widgets/index.js b/packages/cms/lib/modules/image-widgets/index.js index 85802884f..3a1eac491 100644 --- a/packages/cms/lib/modules/image-widgets/index.js +++ b/packages/cms/lib/modules/image-widgets/index.js @@ -28,6 +28,38 @@ module.exports = { label: 'Textual alternative', type: 'string' }, + { + name: 'displaySize', + type: 'select', + label: 'Display size', + def: 'full', + choices: [ + { + value: 'max', + label: "Max (1600x1600)" + }, + { + value: 'full', + label: "Volledig (1140x1140)", + }, + { + value: 'two-thirds', + label: "Medium-groot (760x760)", + }, + { + value: 'one-half', + label: "Medium (570x700)", + }, + { + value: 'one-third', + label: "Medium-klein (380x700)", + }, + { + value: 'one-sixth', + label: "Klein (190x350)", + }, + ] + }, styleSchema.definition('imageStyles', 'Styles for the image'), ], @@ -36,7 +68,7 @@ module.exports = { { name: 'generalGroup', label: 'General', - fields: ['uploadedImage'] + fields: ['uploadedImage', 'displaySize'] }, { name: 'stylingGroup', diff --git a/packages/cms/lib/modules/image-widgets/views/widget.html b/packages/cms/lib/modules/image-widgets/views/widget.html index 8c067ce60..2680b5c06 100644 --- a/packages/cms/lib/modules/image-widgets/views/widget.html +++ b/packages/cms/lib/modules/image-widgets/views/widget.html @@ -4,7 +4,7 @@ {{data.widget.uploadedImageAlt}} diff --git a/packages/cms/lib/modules/openstad-global/lib/arrangeFields.js b/packages/cms/lib/modules/openstad-global/lib/arrangeFields.js index 15ffa4caf..ca955db6c 100644 --- a/packages/cms/lib/modules/openstad-global/lib/arrangeFields.js +++ b/packages/cms/lib/modules/openstad-global/lib/arrangeFields.js @@ -12,7 +12,7 @@ module.exports = [ { name: 'api', label: 'Url & api instellingen', - fields: ['siteId', 'ideaSlug', 'ideaOverviewSlug', 'editIdeaUrl', 'cacheIdeas'] + fields: ['siteId', 'ideaSlug', 'ideaOverviewSlug', 'editIdeaUrl', 'cacheIdeas', 'openstadComponentsUrl'] }, { diff --git a/packages/cms/lib/modules/openstad-global/lib/fields.js b/packages/cms/lib/modules/openstad-global/lib/fields.js index b9d43af16..33ada7867 100644 --- a/packages/cms/lib/modules/openstad-global/lib/fields.js +++ b/packages/cms/lib/modules/openstad-global/lib/fields.js @@ -800,4 +800,12 @@ module.exports = [ choices: rightsChoices, def: 'member' },*/ + + { + type: 'string', + name: 'openstadComponentsUrl', + label: 'Openstad Components URL', + help: 'Specify the URL where the Openstad Components (choice guide, ideas on map etc.) are loaded from. Leave empty to use the default URL.', + def: '' + }, ]; diff --git a/packages/cms/lib/modules/previous-next-button-block-widgets/index.js b/packages/cms/lib/modules/previous-next-button-block-widgets/index.js index 00e24ea0f..361b40216 100755 --- a/packages/cms/lib/modules/previous-next-button-block-widgets/index.js +++ b/packages/cms/lib/modules/previous-next-button-block-widgets/index.js @@ -29,6 +29,13 @@ module.exports = { }); widget.config = config; widget.divId = widget.config.divId; + + widget.openstadComponentsCdn = (req && req.data && req.data.global && req.data.global.openstadComponentsUrl) || self.apos.settings.getOption(req, 'siteConfig').openstadComponentsCdn; + + const containerId = self.apos.utils.generateId(); + widget.containerId = containerId; + widget.cssHelperClassesString = widget.cssHelperClasses ? widget.cssHelperClasses.join(' ') : ''; + widget.formattedContainerStyles = styleSchema.format(containerId, widget.containerStyles); }); return superLoad(req, widgets, next); diff --git a/packages/cms/lib/modules/resource-form-widgets/index.js b/packages/cms/lib/modules/resource-form-widgets/index.js index 44e4188b9..f82bcfdd6 100644 --- a/packages/cms/lib/modules/resource-form-widgets/index.js +++ b/packages/cms/lib/modules/resource-form-widgets/index.js @@ -134,7 +134,7 @@ module.exports = { self.load = function (req, widgets, next) { const styles = openstadMap.defaults.styles; const globalData = req.data.global; - + widgets.forEach(async (widget) => { const resourceType = widget.resource ? widget.resource : false; const resourceInfo = resourceType ? resourcesSchema.find((resourceInfo) => resourceInfo.value === resourceType) : false; diff --git a/packages/cms/lib/modules/resource-overview-widgets/views/widget.html b/packages/cms/lib/modules/resource-overview-widgets/views/widget.html index 26cf8b857..927bbd7eb 100644 --- a/packages/cms/lib/modules/resource-overview-widgets/views/widget.html +++ b/packages/cms/lib/modules/resource-overview-widgets/views/widget.html @@ -22,7 +22,7 @@ {% if data.widget.formattedSearchText %}
- {{data.widget.formattedSearchText | sanitize | safe}} + {{ data.widget.formattedSearchText }}
{% endif %} diff --git a/packages/cms/lib/modules/slider-widgets/index.js b/packages/cms/lib/modules/slider-widgets/index.js index 2292115b7..f98ba7a9c 100644 --- a/packages/cms/lib/modules/slider-widgets/index.js +++ b/packages/cms/lib/modules/slider-widgets/index.js @@ -46,6 +46,38 @@ module.exports = { name: 'image', label: 'Image' }, + { + name: 'displaySize', + type: 'select', + label: 'Display size', + def: 'full', + choices: [ + { + value: 'max', + label: "Max (1600x1600)" + }, + { + value: 'full', + label: "Volledig (1140x1140)", + }, + { + value: 'two-thirds', + label: "Medium-groot (760x760)", + }, + { + value: 'one-half', + label: "Medium (570x700)", + }, + { + value: 'one-third', + label: "Medium-klein (380x700)", + }, + { + value: 'one-sixth', + label: "Klein (190x350)", + }, + ] + }, { name: 'linkUrl', type: 'text', diff --git a/packages/cms/lib/modules/slider-widgets/views/widget.html b/packages/cms/lib/modules/slider-widgets/views/widget.html index 90dd06fa5..3fab21d7b 100644 --- a/packages/cms/lib/modules/slider-widgets/views/widget.html +++ b/packages/cms/lib/modules/slider-widgets/views/widget.html @@ -9,7 +9,7 @@