diff --git a/.bowerrc b/.bowerrc index 6a060253..33085090 100755 --- a/.bowerrc +++ b/.bowerrc @@ -1,4 +1,5 @@ { "directory": "public/lib", - "analytics": false + "analytics": false, + "registry": "https://registry.bower.io" } diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..9d31fe83 --- /dev/null +++ b/.env.example @@ -0,0 +1,124 @@ +# TellForm Configuration File + +################################### +# Common configuration variables +################################### + +# Set this to the path where Mailu data and configuration is stored +# Mac users: Change to a Docker accessible folder +ROOT=/opt/tellform_data + +# Set to what environment you will be running TellForm in (production or development) +NODE_ENV=development + +# Set to a randomly generated 16 bytes string +SECRET_KEY=ChangeMeChangeMe + +# URI of Mongo database that TellForm will connect to +#DO NOT CHANGE +MONGODB_URI=mongodb://mongo/tellform + +# URL Redis server that TellForm will connect to +#DO NOT CHANGE +REDIS_URL=redis://redis:6379 + +# Port that the TellForm Node app will listen on +PORT=5000 + +# Domain that TellForm's admin panel will be hosted at +BASE_URL=tellform.dev + +# Port that SocketIO server (for analytics) will listen on +SOCKET_PORT=20523 + +#Choose what kind of TLS you want. +#Can be either 'cert' (supply your certificates in ./cert/), 'notls' (no https at all) or 'letsencrypt' that autoconfigures your instance with letsencrypt +TLS_FLAVOR=notls + +################################### +# Optional features +################################### + +# Set this to enable coveralls.io support +COVERALLS_REPO_TOKEN= + +# Disable signups for your TellForm instance +SIGNUP_DISABLED=FALSE + +# Disable per-user custom subdomains +SUBDOMAINS_DISABLED=FALSE + +# Url that subdomains will be hosted at (has to have domain name as ADMIN_URL) +# Only used when SUBDOMAINS_DISABLED=FALSE +SUBDOMAIN_URL=*.tellform.dev + +# Enable running TellForm in pm2's 'cluster' mode +ENABLE_CLUSTER_MODE=FALSE + +################################### +# Mail settings +# IMPORTANT: These settings need to be set +# to be set in order for your instance to work +################################### + + + +# Set this to set the username credential of your SMTP service +MAILER_EMAIL_ID= + +# Set this to set the password credential of your SMTP service +MAILER_PASSWORD= + +# Set this to set the email address that all email should be sent from for signup/verification emails +MAILER_FROM= + +# Set this to any services from https://nodemailer.com/smtp/well-known/ to use a 'well-known' email provider +MAILER_SERVICE_PROVIDER= + +# Set these if you are not using a 'MAILER_SERVICE_PROVIDER' and want to specify your SMTP server's address and port +MAILER_SMTP_HOST= +MAILER_SMTP_PORT= + +# Set this if you are using a custom SMTP server that supports SSL +MAILER_SMTP_SECURE + +################################### +# Automatic Admin Creation Settings +################################### + +# Set this to "TRUE" if you wish to automatically create an admin user on startup +CREATE_ADMIN=FALSE + +# Set this to set the email used by your default admin account +ADMIN_EMAIL=admin@admin.com + +# Set this to set the username of your default admin acconut +ADMIN_USERNAME=root + +# Set this to set the password of your default admin account +ADMIN_PASSWORD=root + +################################### +# Advanced settings +################################### + +# Set this to server your websockets server on a seperate URL +SOCKETS_URL= + +# Set this to change the port that TellForm will listen on +PORT=5000 + +# Set this to your Google Analytics ID to enable tracking with GA +GOOGLE_ANALYTICS_ID= + +# Set this to your Sentry.io DSN code to enable front-end JS error tracking with Sentry.io +RAVEN_DSN + +# Set this to set the 'name' meta property in the HTML +APP_NAME= + +# Set this to set the 'keywords' meta property in the HTML +APP_KEYWORDS= + +# Set this to set the 'description' meta property in the HTML head +APP_DESC= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 91df1f8d..76008bce 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +data/ dist .vagrant npm-debug.* diff --git a/Dockerfile b/Dockerfile index 6b145fd1..4c957018 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,33 +4,16 @@ # Run: # docker run -it tellform-prod -FROM phusion/baseimage:0.9.19 -MAINTAINER David Baldwynn +FROM node:10-alpine +MAINTAINER Arielle Baldwynn -# Install Utilities -RUN apt-get update -q \ - && apt-get install -yqq \ - curl \ - ant \ - git \ - gcc \ - make \ - build-essential \ - libkrb5-dev \ - python \ - sudo \ - apt-utils \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Install nodejs -RUN curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - -RUN sudo apt-get install -yq nodejs \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +# Install some needed packages +RUN apk add --no-cache \ + git \ + && rm -rf /tmp/* # Install NPM Global Libraries -RUN npm install --quiet -g grunt bower pm2 && npm cache clean +RUN npm install --quiet -g grunt bower pm2 && npm cache clean --force WORKDIR /opt/tellform RUN mkdir -p /opt/tellform/public/lib @@ -47,6 +30,39 @@ COPY ./gruntfile.js /opt/tellform/gruntfile.js COPY ./server.js /opt/tellform/server.js COPY ./scripts/create_admin.js /opt/tellform/scripts/create_admin.js +# Set default ENV +ENV NODE_ENV=development +ENV SECRET_KEY=ChangeMeChangeMe +#ENV MONGODB_URI=mongodb://mongo/tellform +#ENV REDIS_URL=redis://redis:6379 +ENV PORT=5000 +ENV BASE_URL=localhost +ENV SOCKET_PORT=20523 +ENV SIGNUP_DISABLED=FALSE +ENV SUBDOMAINS_DISABLED=FALSE +ENV ENABLE_CLUSTER_MODE=FALSE +ENV MAILER_EMAIL_ID=tellform@localhost +ENV MAILER_PASSWORD= +ENV MAILER_FROM=tellform@localhost +ENV MAILER_SERVICE_PROVIDER= +ENV MAILER_SMTP_HOST= +ENV MAILER_SMTP_PORT= +ENV MAILER_SMTP_SECURE= + +ENV CREATE_ADMIN=FALSE +ENV ADMIN_EMAIL=admin@tellform.com +ENV ADMIN_USERNAME=root +ENV ADMIN_PASSWORD=root + +ENV APP_NAME=Tellform +ENV APP_KEYWORDS= +ENV APP_DESC= + +# optional ENV settings +ENV COVERALLS_REPO_TOKEN= +ENV GOOGLE_ANALYTICS_ID= +ENV RAVEN_DSN= + # Copies the local package.json file to the container # and utilities docker container cache to not needing to rebuild # and install node_modules/ everytime we build the docker, but only @@ -54,6 +70,8 @@ COPY ./scripts/create_admin.js /opt/tellform/scripts/create_admin.js # Add npm package.json COPY ./package.json /opt/tellform/package.json RUN npm install --only=production --quiet +RUN bower install --allow-root +RUN grunt build # Run TellForm server CMD ["node", "server.js"] diff --git a/INSTALLATION_INSTRUCTIONS.md b/INSTALLATION_INSTRUCTIONS.md index 7734c284..1a871488 100644 --- a/INSTALLATION_INSTRUCTIONS.md +++ b/INSTALLATION_INSTRUCTIONS.md @@ -10,56 +10,7 @@ TellForm Installation Instructions ## Local deployment with Docker -### Prerequisites - -Make you sure have the following packages and versions on your machine: -``` -"node": ">=6.11.2" -"npm": ">=3.3.6" -"bower": ">=1.8.0" -"grunt-cli": ">=1.2.0" -"grunt": ">=0.4.5" -"docker": ">=17.06.0-ce" -"docker-compose": ">=1.14.0" -``` - -### Install dependencies - -``` -$ npm install -``` - -### Prepare .env file: -Create `.env` file at project root folder. Fill in `MAILER_SERVICE_PROVIDER`, `MAILER_EMAIL_ID`, `MAILER_PASSWORD` and `MAILER_FROM`. -``` -APP_NAME=TellForm -BASE_URL=localhost:3000 -PORT=3000 -DB_PORT_27017_TCP_ADDR=tellform-mongo -REDIS_DB_PORT_6379_TCP_ADDR=tellform-redis -MAILER_SERVICE_PROVIDER= -MAILER_EMAIL_ID= -MAILER_PASSWORD= -MAILER_FROM= -SIGNUP_DISABLED=false -SUBDOMAINS_DISABLED=true -DISABLE_CLUSTER_MODE=true -``` - -### Build docker image - -``` -$ docker-compose build -``` - -### Run docker containers with docker-compose - -Create and start mongo & redis docker container: -``` -$ docker-compose up -``` - -Your application should run on port 3000 or the port you specified in your .env file, so in your browser just go to [http://localhost:3000](http://localhost:3000) +Refer to [docker_files](https://github.com/tellform/docker_files). ## AWS AMI Deployment diff --git a/README.md b/README.md index 4f5a35ce..59ca07e0 100755 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ TellForm 2.1.0 ======== +[![Code Shelter](https://www.codeshelter.co/static/badges/badge-flat.svg)](https://www.codeshelter.co/) [![Build Status](https://travis-ci.org/tellform/tellform.svg?branch=master)](https://travis-ci.org/tellform/tellform) ![Project Status](https://img.shields.io/badge/status-2.1.0-green.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3491e86eb7194308b8fc80711d736ede)](https://www.codacy.com/app/david-baldwin/tellform?utm_source=github.com&utm_medium=referral&utm_content=tellform/tellform&utm_campaign=Badge_Grade) + +![Discord](https://img.shields.io/discord/586697165980565504.svg?label=Discord%20Chat) > An *opensource alternative to TypeForm* that can create [stunning mobile-ready forms](https://tellform.com/examples) , surveys and questionnaires. [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/tellform/tellform/tree/master) @@ -97,7 +101,7 @@ MAILER_SERVICE_PROVIDER=SendGrid # Note: MAILER_SMTP_HOST will override MAILER_SERVICE_PROVIDER MAILER_SMTP_HOST=smtp.domain.com MAILER_SMTP_PORT=465 -MAILER_SMTP_SECURE=true +MAILER_SMTP_SECURE=TRUE ``` @@ -119,7 +123,25 @@ Your application should run on port 3000 or the port you specified in your .env To deploy with docker, first install docker [here](https://docs.docker.com/engine/installation/). -Then see this page [here](https://tellform.com/install_docker) for commands on how to deploy your own local TellForm instance. +Then run follow these steps: + +### Step 1: Clone the repo + +`$ git clone https://github.com/tellform/docker_files.git` + +### Step 2: Setup TellForm Configuration + +Create your .env file by copying the .env.dist file included in the repo and changing it to suit your deployment. + +Important: You need to fill out all of the ENV variables in the "Mail Settings" section or your TellForm instance won't work. + +If you want to have https, make sure to change 'TLS_FLAVOR' + +### Step 3: Start your TellForm instance + +`docker-compose up -d` + +TellForm should now be accessible on http://localhost ## Testing Your Application You can run the full test suite included with TellForm with the test task: @@ -203,25 +225,8 @@ TellForm's configuration is done with environment variables. To set an option fo Does your company use TellForm? Help keep the project bug-free and feature rich by [sponsoring the project](https://opencollective.com/tellform#sponsor). - - - - - - - - - -

- - - - - - - - - + + ## Backers @@ -245,8 +250,6 @@ Love our work and community? [Become a backer](https://opencollective.com/tellfo ## Mentions on the Web -[Mister Ad](http://start.mister-ad.biz/newsticker/open-source-alternative-zu-typeform-tellform-in-der-kurzvorstellung/) - [t3n.de](http://t3n.de/news/open-source-alternative-typeform-tellform-707295/) [BootCSS Expo](http://expo.bootcss.com/) diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index 28d2c3f4..f76f6581 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -26,7 +26,7 @@ exports.deleteSubmissions = function(req, res) { var submission_id_list = req.body.deleted_submissions, form = req.form; - FormSubmission.remove({ form: req.form, admin: req.user, _id: {$in: submission_id_list} }, function(err){ + FormSubmission.remove({ form: req.form, _id: {$in: submission_id_list} }, function(err){ if(err){ res.status(400).send({ @@ -55,7 +55,7 @@ exports.deleteSubmissions = function(req, res) { exports.createSubmission = function(req, res) { var timeElapsed = 0; - + if(typeof req.body.timeElapsed === 'number'){ timeElapsed = req.body.timeElapsed; } diff --git a/app/views/500.server.view.pug b/app/views/500.server.view.pug index 3c6fc1b1..7739aabc 100644 --- a/app/views/500.server.view.pug +++ b/app/views/500.server.view.pug @@ -9,4 +9,4 @@ block content div.col-md-12.text-center(style="padding-bottom: 50px;") | #{error} else - div.col-md-12.text-center(style="padding-bottom: 50px;")=__('500_BODY') \ No newline at end of file + div.col-md-12.text-center(style="padding-bottom: 50px;")=__('500_BODY') diff --git a/app/views/form.server.view.pug b/app/views/form.server.view.pug index 67f2b92b..1a14773b 100644 --- a/app/views/form.server.view.pug +++ b/app/views/form.server.view.pug @@ -59,6 +59,9 @@ html(lang='en', xmlns='http://www.w3.org/1999/xhtml') script(type='text/javascript'). socketUrl = "!{socketUrl}" + //JSEP + script(src='https://cdn.jsdelivr.net/npm/jsep@0.3.4/build/jsep.min.js', type='text/javascript') + script(src='/static/lib/jquery/dist/jquery.min.js', type='text/javascript') link(rel='stylesheet', href='/static/lib/font-awesome/css/font-awesome.min.css') link(rel='stylesheet', href='/static/lib/bootstrap/dist/css/bootstrap.min.css') diff --git a/bower.json b/bower.json index 813d5767..7810660e 100755 --- a/bower.json +++ b/bower.json @@ -35,7 +35,7 @@ "angular-translate": "~2.11.0", "ng-translate": "*", "deep-diff": "^0.3.4", - "jsep": "^0.3.1", + "jsep": "0.3.1", "ngclipboard": "^1.1.1", "mobile-detect": "^1.3.3", "socket.io-client": "^1.7.2", diff --git a/config/env/all.js b/config/env/all.js index 7130af77..35fe1db4 100755 --- a/config/env/all.js +++ b/config/env/all.js @@ -40,7 +40,7 @@ module.exports = { options: process.env.MAILER_SMTP_HOST ? { //Uses custom SMTP if MAILER_SMTP_HOST is set host: process.env.MAILER_SMTP_HOST || '', port: process.env.MAILER_SMTP_PORT || 465, - secure: process.env.MAILER_SMTP_SECURE || true, + secure: (process.env.MAILER_SMTP_SECURE === 'TRUE'), auth: { user: process.env.MAILER_EMAIL_ID || '', pass: process.env.MAILER_PASSWORD || '' diff --git a/config/env/development.js b/config/env/development.js index a44816a7..a62673f6 100755 --- a/config/env/development.js +++ b/config/env/development.js @@ -21,7 +21,7 @@ module.exports = { options: process.env.MAILER_SMTP_HOST ? { //Uses custom SMTP if MAILER_SMTP_HOST is set host: process.env.MAILER_SMTP_HOST || '', port: process.env.MAILER_SMTP_PORT || 465, - secure: process.env.MAILER_SMTP_SECURE || true, + secure: (process.env.MAILER_SMTP_SECURE === 'TRUE'), auth: { user: process.env.MAILER_EMAIL_ID || '', pass: process.env.MAILER_PASSWORD || '' diff --git a/config/env/test.js b/config/env/test.js index c6731236..d3a02f24 100755 --- a/config/env/test.js +++ b/config/env/test.js @@ -30,7 +30,7 @@ module.exports = { options: process.env.MAILER_SMTP_HOST ? { //Uses custom SMTP if MAILER_SMTP_HOST is set host: process.env.MAILER_SMTP_HOST || '', port: process.env.MAILER_SMTP_PORT || 587, - secure: process.env.MAILER_SMTP_SECURE || true, + secure: (process.env.MAILER_SMTP_SECURE === 'TRUE'), auth: { user: process.env.MAILER_EMAIL_ID || '', pass: process.env.MAILER_PASSWORD || '' diff --git a/config/express.js b/config/express.js index d5f21587..e0685c2b 100755 --- a/config/express.js +++ b/config/express.js @@ -188,6 +188,24 @@ module.exports = function(db) { level: 9 })); + //Setup i18n + i18n.configure({ + locales: supportedLanguages, + directory: __dirname + '/locales', + defaultLocale: 'en', + cookie: 'userLang' + }); + + app.use(i18n.init); + + app.use(function(req, res, next) { + // express helper for natively supported engines + res.locals.__ = res.__ = function() { + return i18n.__.apply(req, arguments); + }; + + next(); + }); // Set template engine as defined in the config files app.engine('server.view.pug', consolidate.pug); @@ -249,15 +267,6 @@ module.exports = function(db) { app.use(passport.initialize()); app.use(passport.session()); - //Setup i18n - i18n.configure({ - locales: supportedLanguages, - directory: __dirname + '/locales', - defaultLocale: 'en', - cookie: 'userLang' - }); - - app.use(i18n.init); //Visitor Language Detection app.use(function(req, res, next) { @@ -325,7 +334,8 @@ module.exports = function(db) { // Error page res.status(500).render('500', { - error: err.stack + __: i18n.__, + error: err.stack }); }); @@ -334,7 +344,8 @@ module.exports = function(db) { client.captureError(new Error('Page Not Found')); res.status(404).render('404', { url: req.originalUrl, - error: 'Not Found' + error: 'Not Found', + __: i18n.__ }); }); diff --git a/config/locales/fr.json b/config/locales/fr.json index 681f1bd3..c414c39e 100644 --- a/config/locales/fr.json +++ b/config/locales/fr.json @@ -2,20 +2,20 @@ "404_HEADER": "404 - Page non trouvée", "500_HEADER": "500 - Erreur interne du serveur", "404_BODY": "%s n'est pas un chemin valide.", - "500_BODY": "Une erreur inattendue semble s'être produite, pourquoi ne pas essayer d'actualiser votre page? Ou vous pouvez nous contacter si le problème persiste.", - "EMAIL_GREETING": "Bonjour!", - "VERIFICATION_EMAIL_PARAGRAPH_1": "Bienvenue sur TellForm! Voici un lien spécial pour activer votre nouveau compte:", + "500_BODY": "Une erreur inattendue semble s'être produite, pourquoi ne pas essayer d'actualiser votre page ? Ou vous pouvez nous contacter si le problème persiste.", + "EMAIL_GREETING": "Bonjour !", + "VERIFICATION_EMAIL_PARAGRAPH_1": "Bienvenue sur TellForm ! Voici un lien spécial pour activer votre nouveau compte : ", "VERIFICATION_EMAIL_LINK_TEXT": "Activer mon compte", - "VERIFICATION_EMAIL_PARAGRAPH_2": "Merci beaucoup pour l'utilisation de nos services! Si vous avez des questions ou des suggestions, n'hésitez pas à nous envoyer un courriel ici", - "VERIFICATION_EMAIL_SUBJECT": "¡Active su nueva cuenta TellForm!", - "VERIFICATION_EMAIL_TEXT": "Verifique su cuenta haciendo clic en el siguiente enlace, o copiándolo y pegándolo en su navegador: $ {URL}", + "VERIFICATION_EMAIL_PARAGRAPH_2": "Merci infiniment d'utiliser nos services ! Si vous avez des questions ou des suggestions, n'hésitez pas à nous envoyer un courriel ici", + "VERIFICATION_EMAIL_SUBJECT": "Activer votre nouveau compte TellForm !", + "VERIFICATION_EMAIL_TEXT": "Merci de vérifier votre compte en cliquant sur le lien suivant, ou en le copiant dans votre navigateur web : ${URL}", "EMAIL_SIGNATURE": "- L'équipe TellForm", - "WELCOME_EMAIL_PARAGRAPH_1": "Nous aimerions vous accueillir en tant que nouveau membre!", - "WELCOME_EMAIL_PARAGRAPH_2": "Nous espérons que vous apprécierez l'utilisation de TellForm! Si vous avez des problèmes, n'hésitez pas à nous envoyer un e-mail ici", + "WELCOME_EMAIL_PARAGRAPH_1": "Nous aimerions vous accueillir en tant que nouveau membre !", + "WELCOME_EMAIL_PARAGRAPH_2": "Nous espérons que vous apprécierez l'utilisation de TellForm ! Si vous avez des problèmes, n'hésitez pas à nous envoyer un e-mail ici", "WELCOME_EMAIL_SUBJECT": "Bienvenue dans %s!", "WELCOME_EMAIL_TEXT": "Votre compte a été vérifié avec succès.", "RESET_PASSWORD_CONFIRMATION_EMAIL_PARAGRAPH_1": "Ceci est un message de courtoisie pour confirmer que votre mot de passe a été modifié.", - "RESET_PASSWORD_REQUEST_EMAIL_PARAGRAPH_1": "Voici un lien spécial qui vous permettra de réinitialiser votre mot de passe Veuillez noter qu'il expirera dans une heure pour votre protection:", + "RESET_PASSWORD_REQUEST_EMAIL_PARAGRAPH_1": "Voici un lien spécial qui vous permettra de réinitialiser votre mot de passe. Veuillez noter qu'il expirera dans une heure pour votre protection :", "RESET_PASSWORD_REQUEST_EMAIL_LINK_TEXT": "Réinitialiser votre mot de passe", "RESET_PASSWORD_REQUEST_EMAIL_PARAGRAPH_2": "Si vous ne l'avez pas demandé, veuillez ignorer cet e-mail et votre mot de passe restera inchangé." -} \ No newline at end of file +} diff --git a/config/locales/sv.json b/config/locales/sv.json new file mode 100644 index 00000000..63c67daf --- /dev/null +++ b/config/locales/sv.json @@ -0,0 +1,22 @@ +{ + "500_HEADER": "500 - Internt Serverfel", + "404_HEADER": "404 - Sidan hittades inte", + "404_BODY": "%s är inte en giltig sökväg", + "500_BODY": "Ett oväntat fel verkar ha inträffat. Kan du prova med att uppdatera sidan? Eller kan du kontakta oss om problemet återuppstår igen?", + "EMAIL_GREETING": "Hej där!", + "VERIFICATION_EMAIL_PARAGRAPH_1": "Välkommen till TellForm! Här är en speciell länk till dig för att aktivera ditt nya konto:", + "VERIFICATION_EMAIL_LINK_TEXT": "Aktivera mitt konto", + "VERIFICATION_EMAIL_PARAGRAPH_2": "Tack så mycket för att du använder våra tjänster! Om du har några frågor eller förslag är du varmt välkommen att e-posta oss här på", + "VERIFICATION_EMAIL_SUBJECT": "Aktivera ditt nya TellForm-konto!", + "VERIFICATION_EMAIL_TEXT": "Vänligen verifiera ditt konto genom att klicka på den följande länken, eller genom att kopiera och klistra in den i din webbläsare: ${URL}", + "EMAIL_SIGNATURE": "- TellForm-gruppen", + "WELCOME_EMAIL_PARAGRAPH_1": "Vi skulle vilja välkomna dig som vår nyaste medlem!", + "WELCOME_EMAIL_PARAGRAPH_2": "Vi hoppas att du gillar att använda TellForm! Om du stöter på några problem är du varmt välkommen att e-posta oss här på", + "WELCOME_EMAIL_SUBJECT": "Välkommen till %s!", + "WELCOME_EMAIL_TEXT": "Ditt konto har framgångsrikt blivit verifierat.", + "RESET_PASSWORD_CONFIRMATION_EMAIL_PARAGRAPH_1": "Detta är ett artigt meddelande för att bekräfta att ditt lösenord just har ändrats.", + "RESET_PASSWORD_REQUEST_EMAIL_PARAGRAPH_1": "Här är en speciell länk som kommer tillåta dig att återställa ditt lösenord. Vänligen notera att det kommer utgå om en timma för din säkerhet:", + "RESET_PASSWORD_REQUEST_EMAIL_LINK_TEXT": "Återställ Ditt Lösenord", + "RESET_PASSWORD_REQUEST_EMAIL_PARAGRAPH_2": "Om du inte begärde detta, vänligen ignorera detta meddelande och ditt lösenord kommer att förbli oförändrat.", + "RESET_PASSWORD_CONFIRMATION_EMAIL_BODY_1": "RESET_PASSWORD_CONFIRMATION_EMAIL_BODY_1" +} diff --git a/config/socket.io.js b/config/socket.io.js index 9500d538..7ae1d99e 100644 --- a/config/socket.io.js +++ b/config/socket.io.js @@ -9,7 +9,14 @@ var config = require('./config'), // Define the Socket.io configuration method module.exports = function (app, db) { var server = http.createServer(app); - var io = socketio(config.socketPort, { transports: ['websocket', 'polling'] }); + var io; + + // make it possible to only expose one domain + if (process.env.SOCKET_PORT != process.env.PORT) { + io = socketio(config.socketPort, { transports: ['websocket', 'polling'] }); + } else { + io = socketio(server, { transports: ['websocket', 'polling'] }); + } if(config.enableClusterMode){ var redis = require('socket.io-redis'); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..4b619de0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +version: "3" +services: + redis: + restart: always + image: redis + networks: + - back-tier + mongo: + restart: always + image: mongo + volumes: + - ".data/mongo:/data" + networks: + - back-tier + tellform: + build: + context: . + environment: + CREATE_ADMIN: "TRUE" + MONGODB_URI: mongodb://mongo/tellform + REDIS_URL: redis://redis +# volumes: +# - .:/opt/tellform + links: + - mongo + - redis + ports: + - "5000:5000" + depends_on: + - mongo + - redis + networks: + - back-tier + web: + # image: tellform/nginx:stable + build: + context: ./nginx + # image: nginx:1.13 + restart: always + ports: + - "80:80" + - "443:443" + - "20523:20523" + environment: + NODE_ENV: development + #volumes: + # - "$ROOT/certs:/certs" + # - ./nginx/conf.d:/etc/nginx/conf.d + networks: + - back-tier + +networks: + back-tier: + driver: bridge + diff --git a/docs/readme_logos/digitalOcean.png b/docs/readme_logos/digitalOcean.png new file mode 100644 index 00000000..7df2be2b Binary files /dev/null and b/docs/readme_logos/digitalOcean.png differ diff --git a/docs/readme_logos/sentryIO.png b/docs/readme_logos/sentryIO.png new file mode 100644 index 00000000..49c7bc57 Binary files /dev/null and b/docs/readme_logos/sentryIO.png differ diff --git a/docs/readme_logos/sparkPost.png b/docs/readme_logos/sparkPost.png new file mode 100644 index 00000000..e7282850 Binary files /dev/null and b/docs/readme_logos/sparkPost.png differ diff --git a/docs/readme_logos/statusPageIO.png b/docs/readme_logos/statusPageIO.png new file mode 100644 index 00000000..3bd96c4c Binary files /dev/null and b/docs/readme_logos/statusPageIO.png differ diff --git a/docs/readme_logos/stickerMule.png b/docs/readme_logos/stickerMule.png new file mode 100644 index 00000000..ee03354e Binary files /dev/null and b/docs/readme_logos/stickerMule.png differ diff --git a/docs/readme_logos/theRoostStand.png b/docs/readme_logos/theRoostStand.png new file mode 100644 index 00000000..6e00a8e7 Binary files /dev/null and b/docs/readme_logos/theRoostStand.png differ diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 00000000..3959a099 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,19 @@ +FROM alpine:edge +RUN apk add --no-cache nginx certbot openssl python py-jinja2 + +COPY *.py / +COPY conf /conf + +RUN chmod +x /start.py +RUN chmod +x /letsencrypt.py +RUN chmod +x /config.py + +ENV NODE_ENV=development +ENV PORT=5000 +ENV SOCKET_PORT=20523 +ENV TLS_FLAVOR=notls +ENV BASE_URL=localhost +ENV SUBDOMAIN_URL=*.localhost +ENV SOCKETS_URL=ws.localhost + +CMD /start.py diff --git a/nginx/conf/nginx.conf b/nginx/conf/nginx.conf new file mode 100644 index 00000000..42385be7 --- /dev/null +++ b/nginx/conf/nginx.conf @@ -0,0 +1,116 @@ +# Basic configuration +user nginx; +worker_processes 1; +error_log /dev/stderr info; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + # Standard HTTP configuration with slight hardening + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /dev/stdout; + sendfile on; + keepalive_timeout 65; + server_tokens off; + + #Websockets Server + server { + + {% if NODE_ENV == "development" %} + listen {{SOCKET_PORT}}; + {% else %} + listen 80; + listen [::]:80; + server_name {{ SOCKETS_URL }}; + + # Only enable HTTPS if TLS is enabled with no error + {% if TLS and not TLS_ERROR %} + listen 443 ssl; + listen [::]:443 ssl; + + include /etc/nginx/tls.conf; + add_header Strict-Transport-Security max-age=15768000; + + if ($scheme = http) { + return 301 https://$host$request_uri; + } + {% endif %} + + {% endif %} + + location / { + proxy_pass http://tellform:20523; + proxy_read_timeout 90; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + {% if TLS and not TLS_ERROR %} + proxy_set_header X-Forwarded-Proto https; + {% endif %} + } + + {% if TLS_FLAVOR == 'letsencrypt' %} + location ^~ /.well-known/acme-challenge/ { + proxy_pass http://127.0.0.1:8008; + } + {% endif %} + } + + server { + #Add server_name for per-user subdomains + {% if SUBDOMAINS_DISABLED == "FALSE" %} + server_name {{BASE_URL}} {{SUBDOMAIN_URL}}; + {% else %} + server_name {{BASE_URL}}; + {% endif %} + + listen 80; + listen [::]:80; + + # Only enable HTTPS if TLS is enabled with no error + {% if TLS and not TLS_ERROR %} + listen 443 ssl; + listen [::]:443 ssl; + + include /etc/nginx/tls.conf; + add_header Strict-Transport-Security max-age=15768000; + + if ($scheme = http) { + return 301 https://$host$request_uri; + } + {% endif %} + + root /usr/share/nginx/html; + index index.html index.htm; + + location / { + proxy_pass http://tellform:5000; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; + + {% if TLS and not TLS_ERROR %} + proxy_set_header X-Forwarded-Proto https; + {% endif %} + } + + {% if TLS_FLAVOR == 'letsencrypt' %} + location ^~ /.well-known/acme-challenge/ { + proxy_pass http://127.0.0.1:8008; + } + {% endif %} + } +} diff --git a/nginx/conf/tls.conf b/nginx/conf/tls.conf new file mode 100644 index 00000000..af2d9587 --- /dev/null +++ b/nginx/conf/tls.conf @@ -0,0 +1,7 @@ +ssl_protocols TLSv1.1 TLSv1.2; +ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384'; +ssl_prefer_server_ciphers on; +ssl_session_timeout 10m; +ssl_certificate {{ TLS[0] }}; +ssl_certificate_key {{ TLS[1] }}; +ssl_dhparam /certs/dhparam.pem; \ No newline at end of file diff --git a/nginx/config.py b/nginx/config.py new file mode 100644 index 00000000..eca39ce3 --- /dev/null +++ b/nginx/config.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +import jinja2 +import os + +convert = lambda src, dst, args: open(dst, "w").write(jinja2.Template(open(src).read()).render(**args)) + +args = os.environ.copy() + +# TLS configuration +args["TLS"] = { + "cert": ("/certs/cert.pem", "/certs/key.pem"), + "letsencrypt": ("/certs/letsencrypt/live/mailu/fullchain.pem", + "/certs/letsencrypt/live/mailu/privkey.pem"), + "notls": None +}[args["TLS_FLAVOR"]] + +if args["TLS"] and not all(os.path.exists(file_path) for file_path in args["TLS"]): + print("Missing cert or key file, disabling TLS") + args["TLS_ERROR"] = "yes" + + +# Build final configuration paths +convert("/conf/tls.conf", "/etc/nginx/tls.conf", args) +convert("/conf/nginx.conf", "/etc/nginx/nginx.conf", args) +os.system("nginx -s reload") \ No newline at end of file diff --git a/nginx/letsencrypt.py b/nginx/letsencrypt.py new file mode 100644 index 00000000..cb5a098d --- /dev/null +++ b/nginx/letsencrypt.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +import os +import time +import subprocess + + +command = [ + "certbot", + "-n", "--agree-tos", # non-interactive + "-d", os.environ["HOSTNAMES"], + "-m", "{}@{}".format(os.environ["POSTMASTER"], os.environ["DOMAIN"]), + "certonly", "--standalone", + "--server", "https://acme-v02.api.letsencrypt.org/directory", + "--cert-name", "tellform", + "--preferred-challenges", "http", "--http-01-port", "8008", + "--keep-until-expiring", + "--rsa-key-size", "4096", + "--config-dir", "/certs/letsencrypt", + "--post-hook", "./config.py" +] + +# Wait for nginx to start +time.sleep(5) + +# Run certbot every hour +while True: + subprocess.call(command) + time.sleep(3600) diff --git a/nginx/start.py b/nginx/start.py new file mode 100644 index 00000000..4a1946b9 --- /dev/null +++ b/nginx/start.py @@ -0,0 +1,25 @@ +#!/usr/bin/python + +import os +import subprocess + +#Set default port +if not os.environ["PORT"]: + os.environ["PORT"] = "5000" + +#Set default sockets port +if not os.environ["SOCKET_PORT"]: + os.environ["SOCKET_PORT"] = "20523" + +# Actual startup script +if not os.path.exists("/certs/dhparam.pem") and os.environ["TLS_FLAVOR"] != "notls": + os.system("openssl dhparam -out /certs/dhparam.pem 2048") + +if os.environ["TLS_FLAVOR"] == "letsencrypt": + subprocess.Popen(["/letsencrypt.py"]) +elif os.environ["TLS_FLAVOR"] == "cert": + if not os.path.exists("/certs/cert.pem"): + os.system("openssl req -newkey rsa:2048 -x509 -keyout /certs/key.pem -out /certs/cert.pem -days 365 -nodes -subj '/C=NA/ST=None/L=None/O=None/CN=" + os.environ["BASE_URL"] + "'") + +subprocess.call(["/config.py"]) +os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"]) \ No newline at end of file diff --git a/public/form_modules/forms/base/config/i18n/french.js b/public/form_modules/forms/base/config/i18n/french.js index c544ea1f..2db54e34 100644 --- a/public/form_modules/forms/base/config/i18n/french.js +++ b/public/form_modules/forms/base/config/i18n/french.js @@ -14,13 +14,13 @@ angular.module('view-form').config(['$translateProvider', function ($translatePr COMPLETING_NEEDED: '{{answers_not_completed}} réponse(s) doive(nt) être complétée(s)', OPTIONAL: 'facultatif', ERROR_EMAIL_INVALID: 'Merci de rentrer une adresse mail valide', - ERROR_NOT_A_NUMBER: 'Merce de ne rentrer que des nombres', + ERROR_NOT_A_NUMBER: 'Merci de ne rentrer que des nombres', ERROR_URL_INVALID: 'Merci de rentrer une url valide', OK: 'OK', - ENTER: 'presser ENTRÉE', + ENTER: 'Appuyer sur ENTRÉE', YES: 'Oui', NO: 'Non', - NEWLINE: 'presser SHIFT+ENTER pour créer une nouvelle ligne', + NEWLINE: 'Appuyer sur SHIFT+ENTER pour créer une nouvelle ligne', CONTINUE: 'Continuer', LEGAL_ACCEPT: 'J’accepte', LEGAL_NO_ACCEPT: 'Je n’accepte pas', @@ -33,13 +33,13 @@ angular.module('view-form').config(['$translateProvider', function ($translatePr OPTION_PLACEHOLDER: 'Tapez ou sélectionnez une option', ADD_NEW_LINE_INSTR: 'Appuyez sur MAJ + ENTRÉE pour ajouter une nouvelle ligne', ERROR: 'Erreur', - + FORM_404_HEADER: '404 - Le formulaire n\'existe pas', - FORM_404_BODY: 'Le formulaire auquel vous essayez d\'accéder n\'existe pas. Désolé pour ça!', - + FORM_404_BODY: 'Le formulaire auquel vous essayez d\'accéder n\'existe pas. Désolé pour ça !', + FORM_UNAUTHORIZED_HEADER: 'Non autorisé à accéder au formulaire',    FORM_UNAUTHORIZED_BODY1: 'Le formulaire auquel vous essayez d\'accéder est actuellement privé et inaccessible publiquement.', -   FORM_UNAUTHORIZED_BODY2: 'Si vous êtes le propriétaire du formulaire, vous pouvez le définir sur "Public" dans le panneau "Configuration" du formulaire admin.', +   FORM_UNAUTHORIZED_BODY2: 'Si vous êtes le propriétaire du formulaire, vous pouvez le définir en "Public" dans le panneau "Configuration" du formulaire admin.', }); }]); diff --git a/public/form_modules/forms/base/config/i18n/swedish.js b/public/form_modules/forms/base/config/i18n/swedish.js new file mode 100644 index 00000000..4dcbe05a --- /dev/null +++ b/public/form_modules/forms/base/config/i18n/swedish.js @@ -0,0 +1,45 @@ +'use strict'; + +angular.module('view-form').config(['$translateProvider', function ($translateProvider) { + + $translateProvider.translations('se', { + FORM_SUCCESS: 'Formulärsvaret skickades framgångsrikt in!', + REVIEW: 'Granska', + BACK_TO_FORM: 'Gå tillbaka till Formuläret', + EDIT_FORM: 'Ändra denna TellForm', + CREATE_FORM: 'Skapa denna TellForm', + ADVANCEMENT: '{{done}} utav {{total}} svar', + CONTINUE_FORM: 'Fortsätt till Form', + REQUIRED: 'krävs', + COMPLETING_NEEDED: '{{answers_not_completed}} svar behöver färdigställas', + OPTIONAL: 'valfri', + ERROR_EMAIL_INVALID: 'Vänligen ange en giltig e-postadress', + ERROR_NOT_A_NUMBER: 'Vänligen ange endast giltiga nummer', + ERROR_URL_INVALID: 'Vänligen en giltig url', + OK: 'OK', + ENTER: 'tryck ENTER', + YES: 'Ja', + NO: 'Nej', + NEWLINE: 'tryck SHIFT+ENTER för att skapa ny rad', + CONTINUE: 'Fortsätt', + LEGAL_ACCEPT: 'Jag accepterar', + LEGAL_NO_ACCEPT: 'Jag accepterar inte', + DELETE: 'Radera', + CANCEL: 'Avbryt', + SUBMIT: 'Skicka', + UPLOAD_FILE: 'Ladda upp din Fil', + Y: 'J', + N: 'N', + OPTION_PLACEHOLDER: 'Skriv eller välj ett alternativ', + ADD_NEW_LINE_INSTR: 'Tryck SHIFT+ENTER för att lägga till ny rad', + ERROR: 'Fel', + + FORM_404_HEADER: '404 - Formulär Existerar Inte', + FORM_404_BODY: 'Formuläret du försöker besöka till existerar inte. Ursäkta för det!', + + FORM_UNAUTHORIZED_HEADER: 'Inte Auktoriserad att Tillgå Formulär', + FORM_UNAUTHORIZED_BODY1: 'Formuläret du försöker att besöka är för närvarande privat och inte tillgänglig offentligt.', + FORM_UNAUTHORIZED_BODY2: 'Om du är ägaren till formuläret kan du ställa in den till "Offentlig" i panelen "Konfiguration" i formulärets administration.', + }); + +}]); diff --git a/public/modules/core/config/core.client.routes.js b/public/modules/core/config/core.client.routes.js index 01930695..1dc19a3c 100755 --- a/public/modules/core/config/core.client.routes.js +++ b/public/modules/core/config/core.client.routes.js @@ -48,7 +48,7 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope' var authenticator, permissions, user; permissions = next && next.data && next.data.permissions ? next.data.permissions : null; - Auth.ensureHasCurrentUser(User); + Auth.ensureHasCurrentUser(); user = Auth.currentUser; if(user){ diff --git a/public/modules/core/config/i18n/french.js b/public/modules/core/config/i18n/french.js index adfc6318..9177b275 100644 --- a/public/modules/core/config/i18n/french.js +++ b/public/modules/core/config/i18n/french.js @@ -4,12 +4,12 @@ angular.module('core').config(['$translateProvider', function ($translateProvide $translateProvider.translations('fr', { MENU: 'MENU', - SIGNUP_TAB: 'Créer un Compte', + SIGNUP_TAB: 'Créer un compte', SIGNIN_TAB: 'Connexion', SIGNOUT_TAB: 'Créer un compte', - EDIT_PROFILE: 'Modifier Mon Profil', - MY_SETTINGS: 'Mes Paramètres', - CHANGE_PASSWORD: 'Changer mon Mot de Pass', + EDIT_PROFILE: 'Modifier mon profil', + MY_SETTINGS: 'Mes paramètres', + CHANGE_PASSWORD: 'Changer mon mot de passe', TOGGLE_NAVIGATION: 'Basculer la navigation', }); }]); diff --git a/public/modules/core/config/i18n/swedish.js b/public/modules/core/config/i18n/swedish.js new file mode 100644 index 00000000..a8ad0085 --- /dev/null +++ b/public/modules/core/config/i18n/swedish.js @@ -0,0 +1,16 @@ +'use strict'; + +angular.module('core').config(['$translateProvider', function ($translateProvider) { + + $translateProvider.translations('se', { + MENU: 'MENY', + SIGNUP_TAB: 'Registrera konto', + SIGNIN_TAB: 'Logga In', + SIGNOUT_TAB: 'Logga Ut', + EDIT_PROFILE: 'Redigera Profil', + MY_SETTINGS: 'Mina Inställningar', + CHANGE_PASSWORD: 'Byt Lösenord', + TOGGLE_NAVIGATION: 'Växla navigation' + }); + +}]); diff --git a/public/modules/core/controllers/header.client.controller.js b/public/modules/core/controllers/header.client.controller.js index a0c9054d..a84f63d5 100755 --- a/public/modules/core/controllers/header.client.controller.js +++ b/public/modules/core/controllers/header.client.controller.js @@ -5,7 +5,7 @@ angular.module('core').controller('HeaderController', ['$rootScope', '$scope', ' $rootScope.signupDisabled = $window.signupDisabled; - $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User); + $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(); $scope.authentication = $rootScope.authentication = Auth; @@ -23,7 +23,7 @@ angular.module('core').controller('HeaderController', ['$rootScope', '$scope', ' var promise = User.logout(); promise.then(function() { Auth.logout(); - Auth.ensureHasCurrentUser(User); + Auth.ensureHasCurrentUser(); $scope.user = $rootScope.user = null; $state.go('listForms'); diff --git a/public/modules/forms/admin/config/i18n/french.js b/public/modules/forms/admin/config/i18n/french.js index 02955d77..ee3bb4f3 100644 --- a/public/modules/forms/admin/config/i18n/french.js +++ b/public/modules/forms/admin/config/i18n/french.js @@ -10,11 +10,11 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid PUBLIC: 'Public', PRIVATE: "Privé", GA_TRACKING_CODE: "Code de suivi Google Analytics", - DISPLAY_FOOTER: "Pied de formulaire", + DISPLAY_FOOTER: "Afficher le pied de formulaire?", SAVE_CHANGES: 'Enregistrer les modifications', CANCEL: 'Annuler', - DISPLAY_START_PAGE: "Page de démarrage", - DISPLAY_END_PAGE: "Page de fin personnalisée", + DISPLAY_START_PAGE: "Afficher la page de démarrage ?", + DISPLAY_END_PAGE: "Afficher la page de fin personnalisée ?", GENERAL_TAB: 'General', SELF_NOTIFICATIONS_TAB: 'Self notifications', @@ -35,7 +35,7 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid CREATE_A_NEW_FORM: "Créer un nouveau formulaire", CREATE_FORM: "Créer un formulaire", CREATED_ON: 'Créé le', - MY_FORMS: 'Mes formes', + MY_FORMS: 'Mes formulaires', NAME: "Nom", LANGUE: 'Langue', FORM_PAUSED: 'Formulaire en pause', @@ -69,7 +69,7 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid COPY_AND_PASTE: "Copiez et collez ceci pour ajouter votre TellForm à votre site Web", CHANGE_WIDTH_AND_HEIGHT: "Changez les valeurs de largeur et de hauteur pour mieux vous convenir", POWERED_BY: "Alimenté par", - TELLFORM_URL: "Votre TellForm est en permanence sur cette URL", + TELLFORM_URL: "Votre TellForm est disponible à cette URL", // Modifier la vue de formulaire DISABLED: "Désactivé", @@ -145,7 +145,7 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid // Vue de conception BACKGROUND_COLOR: "Couleur d'arrière-plan", - DESIGN_HEADER: "Changez l'apparence de votre formulaire", + DESIGN_HEADER: "Changer l'apparence de votre formulaire", QUESTION_TEXT_COLOR: "Couleur du texte de la question", ANSWER_TEXT_COLOR: "Couleur du texte de la réponse", BTN_BACKGROUND_COLOR: "Couleur d'arrière-plan du bouton", diff --git a/public/modules/forms/admin/config/i18n/swedish.js b/public/modules/forms/admin/config/i18n/swedish.js new file mode 100644 index 00000000..1c24245c --- /dev/null +++ b/public/modules/forms/admin/config/i18n/swedish.js @@ -0,0 +1,189 @@ +'use strict'; + +angular.module('forms').config(['$translateProvider', function ($translateProvider) { + + $translateProvider.translations('sv', { + // Konfigurera Formulär Tab Vy + ADVANCED_SETTINGS: 'Avancerade Inställningar', + FORM_NAME: 'Namn På Formulär', + FORM_STATUS: 'Status På Formulär', + PUBLIC: 'Offentlig', + PRIVATE: 'Privat', + GA_TRACKING_CODE: 'Google Analytics Spårningskod', + DISPLAY_FOOTER: 'Visa Formulär Footer?', + SAVE_CHANGES: 'Spara Ändringar', + CANCEL: 'Avbryt', + DISPLAY_START_PAGE: 'Visa Startsida?', + DISPLAY_END_PAGE: 'Visa Anpassad Avslutningssida?', + + // Lista Formulär-vy + CREATE_A_NEW_FORM: 'Skapa ett nytt formulär', + CREATE_FORM: 'Skapa formulär', + CREATED_ON: 'Skapad den', + MY_FORMS: 'Mina Formulär', + NAME: 'Namn', + SPRACHE: 'Språk', + FORM_PAUSED: 'Formulär pausat', + + // Redigera Fält Modal + EDIT_FIELD: 'Redigera detta fält', + SAVE_FIELD: 'Spara', + ON: 'PÅ', + AUS: 'AV', + REQUIRED_FIELD: 'Obligatoriskt', + LOGIC_JUMP: 'Logiskt Hopp', + SHOW_BUTTONS: 'Ytterligare Knappar', + SAVE_START_PAGE: 'Spara', + + // Admin-vy + ARE_YOU_SURE: "Är du ABSOLUT säker?", + READ_WARNING: 'Oförväntade dåliga saker kommer hända om du inte läser detta!', + DELETE_WARNING1: 'Denna handling kan INTE göras ogjord. Den kommer att permanent radera "', + DELETE_WARNING2: '"Formuläret och alla associerade inskick.', + DELETE_CONFIRM: 'Vänligen skriv in namnet av formuläret för att bekräfta', + I_UNDERSTAND: "Jag förstår konsekvenserna, radera detta formulär.", + DELETE_FORM_SM: 'Radera', + DELETE_FORM_MD: 'Radera Formulär', + DELETE: 'Radera', + FORM: 'Formulär', + VIEW: 'Vy', + LIVE: 'Live', + PREVIEW: 'Förhandsvy', + COPY: 'Kopiera', + COPY_AND_PASTE: 'Kopiera och Klistra in detta för att lägga till din TellForm till din hemsida.', + CHANGE_WIDTH_AND_HEIGHT: 'Ändra bredd- och höjdvärden för att det ska passa dig bäst', + POWERED_BY: 'Genererad av', + TELLFORM_URL: "Din TellForm är permanent på denna URL", + + // Redigera Form-vy + DISABLED: 'Avaktiverat', + JA: 'JA', + NO: 'NEJ', + ADD_LOGIC_JUMP: 'Lägg till Logic Jump', + ADD_FIELD_LG: 'Klicka för att Lägga Till Nytt Fält', + ADD_FIELD_MD: 'Lägg Till Nytt Fält', + ADD_FIELD_SM: 'Lägg Till Fält', + EDIT_START_PAGE: 'Redigera Startsida', + EDIT_END_PAGE: 'Redigera Slutsida', + WELCOME_SCREEN: 'Startsida', + END_SCREEN: 'Slutsida', + INTRO_TITLE: 'Titel', + INTRO_PARAGRAPH: "Stycke", + INTRO_BTN: 'Startknapp', + TITLE: "Titel", + PARAGRAPH: "Stycke", + BTN_TEXT: 'Gå Tillbaka Knapp', + BUTTONS: 'Knappar', + BUTTON_TEXT: 'Text', + BUTTON_LINK: 'Länk', + ADD_BUTTON: 'Lägg Till Knapp', + PREVIEW_FIELD: 'Förhandsgranska Fråga', + QUESTION_TITLE: 'Titel', + QUESTION_DESCRIPTION: 'Beskrivning', + OPTIONS: 'Alternativ', + ADD_OPTION: 'Lägg Till Alternativ', + NUM_OF_STEPS: 'Antal Steg', + CLICK_FIELDS_FOOTER: 'Klicka på fälten för att lägga till dem här', + IF_THIS_FIELD: 'Om detta fält', + IS_EQUAL_TO: 'är lika med', + IS_NOT_EQUAL_TO: 'inte lika med', + IS_GREATER_THAN: 'är större än', + IS_GREATER_OR_EQUAL_THAN: 'är större eller lika med än', + IS_SMALLER_THAN: 'är mindre än', + IS_SMALLER_OR_EQUAL_THAN: 'är mindre eller lika med än', + CONTAINS: 'innehåller', + DOES_NOT_CONTAINS: 'inte innehåller', + ENDS_WITH: 'slutar med', + DOES_NOT_END_WITH: 'inte slutar med', + STARTS_WITH: 'börjar med', + DOES_NOT_START_WITH: 'inte börjar med', + THEN_JUMP_TO: 'hoppa då till', + + // Redigera Inskicks-vy + TOTAL_VIEWS: 'totalt antal unika besök', + RESPONSES: 'svar', + COMPLETION_RATE: 'grad av fullföljande', + AVERAGE_TIME_TO_COMPLETE: 'snitt på tid för fullföljande', + + DESKTOP_AND_LAPTOP: 'Datorer', + TABLETS: "Plattor", + PHONES: 'Telefoner', + OTHER: 'Andra', + UNIQUE_VISITS: 'Unika Besök', + + FIELD_TITLE: 'Titel på fält', + FIELD_VIEWS: 'Vyer på fält', + FIELD_DROPOFF: 'Fullföljande på fält', + FIELD_RESPONSES: 'Svar på fält', + DELETE_SELECTED: 'Ausgewählte löschen', + EXPORT_TO_EXCEL: 'Exportera till Excel', + EXPORT_TO_CSV: 'Exportera till CSV', + EXPORT_TO_JSON: 'Exportera till JSON', + PERCENTAGE_COMPLETE: 'Procent fullföljt', + TIME_ELAPSED: 'Tid som gått', + DEVICE: 'Utrustning', + LOCATION: 'Ort', + IP_ADDRESS: 'IP-Adress', + DATE_SUBMITTED: 'Datum för inskick', + + // Designvy + BACKGROUND_COLOR: 'Bakgrundsfärg', + DESIGN_HEADER: 'Ändra hur ditt Formulär ser ut', + QUESTION_TEXT_COLOR: 'Frågetextens färg', + ANSWER_TEXT_COLOR: 'Svarstextens färg', + BTN_BACKGROUND_COLOR: 'Knappens bakgrundsfärg', + BTN_TEXT_COLOR: 'Knappens textfärg', + + // Delningsvy + EMBED_YOUR_FORM: 'Bädda in ditt Formulär', + SHARE_YOUR_FORM: 'Dela ditt Formulär', + + // Admin-tab + CREATE_TAB: 'Skapa', + DESIGN_TAB: 'Designa', + CONFIGURE_TAB: 'Konfigurera', + ANALYZE_TAB: 'Analysera', + SHARE_TAB: 'Dela', + + // Fälttyper + SHORT_TEXT: 'Korttext', + EMAIL: 'E-post', + MULTIPLE_CHOICE: 'Flervalsfråga', + DROPDOWN: 'Rullgardinslista', + DATE: 'Datum', + PARAGRAPH_T: "Stycke", + YES_NO: 'Ja / Nej', + LEGAL: "Juridiskt", + RATING: 'Betygssättning', + NUMBERS: 'Nummer', + SIGNATURE: "Signatur", + FILE_UPLOAD: 'Filuppladdning', + OPTION_SCALE: 'Alternativskala', + PAYMENT: "Betalning", + STATEMENT: 'Uttalande', + LINK: 'Länk', + + // Förhandsgranskning Formulär + FORM_SUCCESS: 'Formulär framgångsrikt inskickat!', + REVIEW: 'Granska', + BACK_TO_FORM: 'Gå Tillbaka till Formulär', + EDIT_FORM: 'Redigera denna TellForm', + ADVANCEMENT: '{{done}} av {{total}} svarade', + CONTINUE_FORM: 'Fortsätt till Formulär', + REQUIRED: 'obligatorisk', + COMPLETING_NEEDED: '{{answers_not_completed}} svar kräver komplettering', + OPTIONAL: 'valfri', + ERROR_EMAIL_INVALID: 'Vänligen ange en giltig e-postadress', + ERROR_NOT_A_NUMBER: 'Vänligen ange endast giltiga nummer', + ERROR_URL_INVALID: 'Vänligen en giltig URL', + OK: 'OK', + ENTER: 'tryck ENTER', + NEWLINE: 'tryck SHIFT+ENTER för att skapa ny rad', + CONTINUE: 'Fortsätt', + LEGAL_ACCEPT: "Jag accepterar", + LEGAL_NO_ACCEPT: "Jag accepterar inte", + SUBMIT: 'Skicka', + UPLOAD_FILE: 'Ladda upp din Fil' + }); + +}]); diff --git a/public/modules/forms/base/css/form.css b/public/modules/forms/base/css/form.css index 0f440500..2edc70d7 100644 --- a/public/modules/forms/base/css/form.css +++ b/public/modules/forms/base/css/form.css @@ -130,6 +130,7 @@ div.form-fields { border: 1px solid #000; border: 1px solid rgba(0,0,0,.2); margin-right: 7px; + margin-top: 1px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; diff --git a/public/modules/users/config/i18n/french.js b/public/modules/users/config/i18n/french.js index cb8ceae3..3bc22b56 100644 --- a/public/modules/users/config/i18n/french.js +++ b/public/modules/users/config/i18n/french.js @@ -5,9 +5,9 @@ angular.module('users').config(['$translateProvider', function ($translateProvid $translateProvider.translations('fr', { ACCESS_DENIED_TEXT: 'Vouz n’êtes pas autorisé à accéder à cette page.', USERNAME_LABEL: 'Nom d’utilisateur', - PASSWORD_LABEL: 'Mot de Passe', + PASSWORD_LABEL: 'Mot de passe', CURRENT_PASSWORD_LABEL: 'Mot de passe actuel', - NEW_PASSWORD_LABEL: 'Nouveau Mot de Passe', + NEW_PASSWORD_LABEL: 'Nouveau mot de passe', VERIFY_PASSWORD_LABEL: 'Vérifier le mot de passe', UPDATE_PASSWORD_LABEL: 'Mettre à jour le mot de passe', FIRST_NAME_LABEL: 'Prénom', @@ -15,37 +15,37 @@ angular.module('users').config(['$translateProvider', function ($translateProvid LANGUAGE_LABEL: 'Langue', EMAIL_LABEL: 'Email', - UPDATE_PROFILE_BTN: 'Modifier le Profil', + UPDATE_PROFILE_BTN: 'Modifier le profil', PROFILE_SAVE_SUCCESS: 'Profil enregistré avec succès', - PROFILE_SAVE_ERROR: 'Erreur: impossible d’enregistrer votre Profile.', + PROFILE_SAVE_ERROR: 'Erreur: impossible d’enregistrer votre profil.', FORGOT_PASSWORD_LINK: 'Mot de passe oublié ?', - REVERIFY_ACCOUNT_LINK: 'Re-envoyez un email de vérification', + REVERIFY_ACCOUNT_LINK: 'Re-envoyer un email de vérification', SIGNIN_BTN: 'Connexion', SIGNUP_BTN: 'Créer un compte', - SAVE_PASSWORD_BTN: 'Enregistrer votre nouveau Mot de Passe', + SAVE_PASSWORD_BTN: 'Enregistrer votre nouveau mot de passe', - SUCCESS_HEADER: 'Votre Compte a été enregistré !', - SUCCESS_TEXT: 'Votre compte Tellform a été crée avec succès.', - VERIFICATION_EMAIL_SENT: 'Un email de verification a été envoyer à', + SUCCESS_HEADER: 'Votre compte a été enregistré !', + SUCCESS_TEXT: 'Votre compte Tellform a été créé avec succès.', + VERIFICATION_EMAIL_SENT: 'Un email de verification a été envoyé à', NOT_ACTIVATED_YET: 'Mais votre compte n\'est pas activé', - BEFORE_YOU_CONTINUE: 'Avant de continuer, vous devez valider votre adresse mail. Merci de vérifier votre boite mail. Si vous ne l’avez pas reçu dans les prochaines 24h, contactez-nous a ', + BEFORE_YOU_CONTINUE: 'Avant de continuer, vous devez valider votre adresse mail. Merci de vérifier votre boîte mail. Si vous ne l’avez pas reçu dans les prochaines 24h, contactez-nous à ', CHECK_YOUR_EMAIL: 'Vérifiez vos emails, et cliquez sur le lien de validation pour activer votre compte. Si vous avez une question contactez-nous à', PASSWORD_RESTORE_HEADER: 'Mot de passe perdu', ENTER_YOUR_EMAIL: 'Entrer votre email', SUBMIT_BTN: 'Enregistrer', - ASK_FOR_NEW_PASSWORD: 'Demander un nouveau mot de pass ', + ASK_FOR_NEW_PASSWORD: 'Demander un nouveau mot de passe ', PASSWORD_RESET_INVALID: 'Ce lien de réinitialisation de mot de passe a déjà expiré', PASSWORD_RESET_SUCCESS: 'Mot de passe réinitialisé avec succès', PASSWORD_CHANGE_SUCCESS: 'Mot de passe enregistré avec succès', - CONTINUE_TO_LOGIN: 'Allez à la page de connexion', + CONTINUE_TO_LOGIN: 'Aller à la page de connexion', VERIFY_SUCCESS: 'Votre compte est activé !', - VERIFY_ERROR: 'Le lien de vérification est invalide ou à expiré', + VERIFY_ERROR: 'Le lien de vérification est invalide ou a expiré', ERROR: 'Erreur' }); diff --git a/public/modules/users/config/i18n/swedish.js b/public/modules/users/config/i18n/swedish.js new file mode 100644 index 00000000..a366048e --- /dev/null +++ b/public/modules/users/config/i18n/swedish.js @@ -0,0 +1,71 @@ +'use strict'; + +angular.module('users').config(['$translateProvider', function ($translateProvider) { + + $translateProvider.translations('sv', { + ACCESS_DENIED_TEXT: 'Du behöver vara inloggad för att kunna besöka denna sida', + USERNAME_OR_EMAIL_LABEL: 'Användarnamn eller E-post', + USERNAME_LABEL: 'Användarnamn', + PASSWORD_LABEL: 'Lösenord', + CURRENT_PASSWORD_LABEL: 'Nuvarande Lösenord', + NEW_PASSWORD_LABEL: 'Nytt Lösenord', + VERIFY_PASSWORD_LABEL: 'Bekräfta Lösenord', + UPDATE_PASSWORD_LABEL: 'Uppdatera Lösenord', + FIRST_NAME_LABEL: 'Förnamn', + LAST_NAME_LABEL: 'Efternamn', + LANGUAGE_LABEL: 'Språk', + EMAIL_LABEL: 'E-post', + + SIGNUP_ACCOUNT_LINK: 'Har du inte redan ett konto? Registrera dig här', + SIGN_IN_ACCOUNT_LINK: 'Har du redan ett konto? Logga in här', + SIGNUP_HEADER_TEXT: 'Registrera', + SIGNIN_HEADER_TEXT: 'Logga in', + + SIGNUP_ERROR_TEXT: 'Kunde inte slutföra registrering på grund av fel', + ENTER_ACCOUNT_EMAIL: 'Ange e-postadress för ditt konto.', + RESEND_VERIFICATION_EMAIL: 'Skicka om E-post för Verifiering', + SAVE_CHANGES: 'Spara Ändringar', + CANCEL_BTN: 'Avbryt', + + EDIT_PROFILE: 'Redigera din profil', + UPDATE_PROFILE_BTN: 'Uppdatera Profil', + PROFILE_SAVE_SUCCESS: 'Profil sparades framgångsrikt', + PROFILE_SAVE_ERROR: 'Kunde Inte Spara Din Profil.', + CONNECTED_SOCIAL_ACCOUNTS: 'Kopplade sociala konton', + CONNECT_OTHER_SOCIAL_ACCOUNTS: 'Koppla andra sociala konton', + + FORGOT_PASSWORD_LINK: 'Glömt ditt lösenord?', + REVERIFY_ACCOUNT_LINK: 'Skicka om e-postmeddelande för verifiering', + + SIGNIN_BTN: 'Logga in', + SIGNUP_BTN: 'Registrera', + SAVE_PASSWORD_BTN: 'Spara Lösenord', + + SUCCESS_HEADER: 'Registrering Framgånsrik', + SUCCESS_TEXT: 'Du har framgångsrikt registrerat ett konto på TellForm.', + VERIFICATION_EMAIL_SENT: 'Ett Verifieringsmeddelande har blivit Skickat', + VERIFICATION_EMAIL_SENT_TO: 'Ett verifieringsmeddelande har blivit skickat till', + NOT_ACTIVATED_YET: 'Men ditt konto är ännu inte aktiverat', + BEFORE_YOU_CONTINUE: 'Innan du fortsätter, försäkra dig om att kolla din e-post för vår verifiering. Om du inte tar emot den inom 24 timmar så skicka oss ett meddelande på ', + CHECK_YOUR_EMAIL: 'Kolla din e-post och klicka på aktiveringslänken för att aktivera ditt konto. Om du har några frågor så skicka oss ett meddelande på ', + CONTINUE: 'Fortsätt', + + PASSWORD_RESTORE_HEADER: 'Återställ ditt lösenord', + ENTER_YOUR_EMAIL: 'Ange e-postadressen till ditt konto.', + SUBMIT_BTN: 'Skicka', + + ASK_FOR_NEW_PASSWORD: 'Fråga efter ny lösenordsåterställning', + PASSWORD_RESET_INVALID: 'Länken till återställning av lösenord är ogiltig', + PASSWORD_RESET_SUCCESS: 'Lösenordet återställdes framgångsrikt', + PASSWORD_CHANGE_SUCCESS: 'Lösenordet ändrades framgångsrikt', + RESET_PASSWORD: 'Återställ ditt lösenord', + CHANGE_PASSWORD: 'Ändra ditt lösenord', + + CONTINUE_TO_LOGIN: 'Fortsätt till logga in-sidan', + + VERIFY_SUCCESS: 'Kontot framgångsrikt aktiverat', + VERIFY_ERROR: 'Verifieringslänken är ogiltig eller har utgått', + ERROR: 'Fel' + }); + +}]); diff --git a/public/modules/users/controllers/authentication.client.controller.js b/public/modules/users/controllers/authentication.client.controller.js index 811e855f..2048e1fb 100755 --- a/public/modules/users/controllers/authentication.client.controller.js +++ b/public/modules/users/controllers/authentication.client.controller.js @@ -15,7 +15,7 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca User.login($scope.credentials).then( function(response) { Auth.login(response); - $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User); + $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(); if(statesToIgnore.indexOf($state.previous.state.name) === -1) { $state.go($state.previous.state.name, $state.previous.params); @@ -24,7 +24,7 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca } }, function(error) { - $rootScope.user = Auth.ensureHasCurrentUser(User); + $rootScope.user = Auth.ensureHasCurrentUser(); $scope.user = $rootScope.user; $scope.error = error; diff --git a/public/modules/users/services/auth.client.service.js b/public/modules/users/services/auth.client.service.js index 806db08f..2c315001 100644 --- a/public/modules/users/services/auth.client.service.js +++ b/public/modules/users/services/auth.client.service.js @@ -1,7 +1,7 @@ 'use strict'; -angular.module('users').factory('Auth', ['$window', - function($window) { +angular.module('users').factory('Auth', ['$window', 'User', + function($window, User) { var userState = { isLoggedIn: false @@ -16,7 +16,7 @@ angular.module('users').factory('Auth', ['$window', // Note: we can't make the User a dependency of Auth // because that would create a circular dependency // Auth <- $http <- $resource <- LoopBackResource <- User <- Auth - ensureHasCurrentUser: function(User) { + ensureHasCurrentUser: function() { if (service._currentUser && service._currentUser.username) { return service._currentUser; } else if ($window.user){ diff --git a/scripts/create_admin.js b/scripts/create_admin.js index 6d5ee5c6..b676f92e 100644 --- a/scripts/create_admin.js +++ b/scripts/create_admin.js @@ -5,14 +5,14 @@ var config = require('../config/config'), exports.run = function(app, db, cb) { var User = mongoose.model('User'); - var email = 'admin@admin.com' || config.admin.email; + var email = config.admin.email || 'admin@admin.com'; var newUser = new User({ firstName: 'Admin', lastName: 'Account', email: email, - username: 'root' || config.admin.username, - password: 'root' || config.admin.password, + username: config.admin.username || 'root', + password: config.admin.password || 'root', provider: 'local', roles: ['admin', 'user'] }); diff --git a/server.js b/server.js index 725a6842..6dfe8a96 100755 --- a/server.js +++ b/server.js @@ -43,7 +43,8 @@ const smtpTransport = nodemailer.createTransport(config.mailer.options); smtpTransport.verify(function(error, success) { if (error) { console.error(chalk.red('Your mail configuration is incorrect: ' + error)); - process.exit(-1); + // verify but to abort! + // process.exit(-1); } }); @@ -51,7 +52,7 @@ smtpTransport.verify(function(error, success) { var app = require('./config/express')(db); //Create admin account -if (process.env.CREATE_ADMIN_ACCOUNT === 'TRUE') { +if (process.env.CREATE_ADMIN === 'TRUE') { var create_admin = require('./scripts/create_admin'); create_admin.run(app, db, function(err){