Commit c1790713 authored by hholder's avatar hholder

Update .gitlab-ci.yml

parent 7e6734f3
......@@ -23,7 +23,7 @@ We use the Developer Certificate of Origin (DCO) as a additional safeguard
for the CodiMD project. This is a well established and widely used
mechanism to assure contributors have confirmed their right to license
their contribution under the project's license.
Please read [contribute/developer-certificate-of-origin][dcofile].
Please read [docs/legal/developer-certificate-of-origin.txt][dcofile].
If you can certify it, then just add a line to every git commit message:
````
......
......@@ -39,8 +39,9 @@ all of these:
* [Docker](docs/setup/docker.md)
* [Kubernetes](docs/setup/kubernetes.md)
* [Cloudron](docs/setup/cloudron.md)
* [LinuxServer.io (multi-arch docker)](docs/setup/docker-linuxserver.md)
* [Heroku](docs/setup/heroku.md)
* [manual setup](docs/setup/manual-setup.md)
* [Manual setup](docs/setup/manual-setup.md)
If you do not wish to run your own setup, you can find a commercial offering at
https://hackmd.io. This is not the same codebase as this one, but it is a very
......@@ -85,7 +86,7 @@ which lets you use CodiMD from the comfort of your command line.
Licensed under AGPLv3. For our list of contributors, see [AUTHORS](AUTHORS).
[matrix.org-image]: https://img.shields.io/badge/Matrix.org-%23CodiMD@matrix.org-green.svg
[matrix.org-image]: https://img.shields.io/matrix/codimd:matrix.org?logo=matrix&server_fqdn=matrix.org
[matrix.org-url]: https://riot.im/app/#/room/#codimd:matrix.org
[travis-image]: https://travis-ci.org/codimd/server.svg?branch=master
[travis-url]: https://travis-ci.org/codimd/server
......@@ -100,4 +101,4 @@ Licensed under AGPLv3. For our list of contributors, see [AUTHORS](AUTHORS).
[codimd-community]: https://community.codimd.org
[codimd-community-calls]: https://community.codimd.org/t/codimd-community-call/19
[social-mastodon]: https://social.codimd.org/mastodon
[social-mastodon-image]: https://img.shields.io/badge/social-mastodon-3c99dc.svg
[social-mastodon-image]: https://img.shields.io/mastodon/follow/18547?domain=https%3A%2F%2Fsocial.snopyta.org&style=social
......@@ -113,7 +113,7 @@ if (config.csp.enable) {
}
i18n.configure({
locales: ['en', 'zh-CN', 'zh-TW', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da', 'ko', 'id', 'sr', 'vi'],
locales: ['en', 'zh-CN', 'zh-TW', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da', 'ko', 'id', 'sr', 'vi', 'ar'],
cookie: 'locale',
indent: ' ', // this is the style poeditor.com exports it, this creates less churn
directory: path.join(__dirname, '/locales'),
......
......@@ -91,7 +91,7 @@
"saml": {
"idpSsoUrl": "change: authentication endpoint of IdP",
"idpCert": "change: certificate file path of IdP in PEM format",
"issuer": "change or delete: identity of the service provider (default: serverurl)",
"issuer": "change or delete: identity of the service provider (default: config.serverURL)",
"identifierFormat": "change or delete: name identifier format (default: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress')",
"disableRequestedAuthnContext": "change or delete: true to allow any authentication method, false restricts to password authentication method (default: false)",
"groupAttribute": "change or delete: attribute name for group list (ex: memberOf)",
......
......@@ -26,13 +26,13 @@ to `config.json` before filling in your own details.
| --------- | ------ | ----------- |
| `allowPDFExport` | `true` | Whether or not PDF export is offered. |
| `db` | `{ "dialect": "sqlite", "storage": "./db.codimd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) |
| `dbURL` | `mysql://localhost:3306/database` | set the db URL; if set, then db config (below) won't be applied |
| `dbURL` | `mysql://localhost:3306/database` | Set the db in URL style. If set, then the relevant `db` config entries will be overridden. |
| `forbiddenNoteIDs` | `['robots.txt']` | disallow creation of notes, even if `allowFreeUrl` is `true` |
| `loglevel` | `info` | Defines what kind of logs are provided to stdout. |
| `imageUploadType` | `imgur`, `s3`, `minio`, `azure`, `lutim` or `filesystem`(default) | Where to upload images. For S3, see our Image Upload Guides for [S3](guides/s3-image-upload.md) or [Minio](guides/minio-image-upload.md)|
| `loglevel` | `info` | Defines what kind of logs are provided to stdout. Available options: `debug`, `verbose`, `info`, `warn`, `error` |
| `imageUploadType` | `imgur`, `s3`, `minio`, `azure`, `lutim` or `filesystem`(default) | Where to upload images. For S3, see our Image Upload Guides for [S3](guides/s3-image-upload.md) or [MinIO](guides/minio-image-upload.md)|
| `sourceURL` | `https://github.com/codimd/server/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
| `staticCacheTime` | `1 * 24 * 60 * 60 * 1000` | static file cache time |
| `tooBusyLag` | `70` | CPU time for one eventloop tick until node throttles connections. (milliseconds) |
| `tooBusyLag` | `70` | CPU time for one event loop tick until node throttles connections. (milliseconds) |
| `heartbeatInterval` | `5000` | socket.io heartbeat interval |
| `heartbeatTimeout` | `10000` | socket.io heartbeat timeout |
| `documentMaxLength` | `100000` | note max length |
......@@ -81,20 +81,20 @@ these are rarely used for various reasons.
| variables | example values | description |
| --------- | ------ | ----------- |
| `allowGravatar` | `true` or `false` | set to `false` to disable gravatar as profile picture source on your instance |
| `allowGravatar` | `true` or `false` | set to `false` to disable Gravatar as profile picture source on your instance |
| `useCDN` | `true` or `false` | set to use CDN resources or not (default is `true`) |
## Users and Privileges
| variables | example values | description |
| --------- | ------ | ----------- |
| `allowAnonymous` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `allowAnonymousEdits` | `true` or `false` | if `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `allowFreeURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `defaultPermission` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | set notes default permission (only applied on signed users) |
| `sessionName` | `connect.sid` | cookie session name |
| `sessionLife` | `14 * 24 * 60 * 60 * 1000` | cookie session life |
| `sessionSecret` | `secret` | cookie session secret | If none is set, one will randomly generated on each startup, meaning all your users will be logged out. |
| `allowAnonymous` | `true` or `false` | Set to allow anonymous usage (default is `true`). |
| `allowAnonymousEdits` | `true` or `false` | If `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`). |
| `allowFreeURL` | `true` or `false` | Set to allow new note creation by accessing a nonexistent note URL. This is the behavior familiar from [Etherpad](https://github.com/ether/etherpad-lite). |
| `defaultPermission` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | Set notes default permission (only applied on signed-in users). |
| `sessionName` | `connect.sid` | Cookie session name. |
| `sessionLife` | `14 * 24 * 60 * 60 * 1000` (14 days) | Cookie session life time in milliseconds. |
| `sessionSecret` | `secret` | Cookie session secret. If none is set, one will randomly generated on each startup, meaning all your users will be logged out. |
## Login methods
......@@ -105,8 +105,8 @@ Most of these have never been documented for the config.json, feel free to expan
| variables | example values | description |
| --------- | ------ | ----------- |
| `email` | `true` or `false` | set to allow email signin |
| `allowEmailRegister` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
| `email` | `true` or `false` | Set to allow email sign-in. The default is `true`. |
| `allowEmailRegister` | `true` or `false` | Set to allow registration of new accounts using an email address. If set to `false`, you can still create accounts using the command line - see `bin/manage_users` for details. This setting has no effect if `email` is `false`. The default for `allowEmailRegister` is `true`. |
### Dropbox Login
### Facebook Login
......@@ -138,8 +138,8 @@ Most of these have never been documented for the config.json, feel free to expan
| `s3bucket` | `YOUR_S3_BUCKET_NAME` | bucket name when `imageUploadType` is set to `s3` or `minio` |
### Azure Blob Storage
### imgur
### Minio
### Imgur
### MinIO
| variables | example values | description |
| --------- | ------ | ----------- |
......
......@@ -30,12 +30,12 @@ defaultNotePath can't be set from env-vars
| -------- | ------------- | ----------- |
| `CMD_ALLOW_PDF_EXPORT` | `true` or `false` | Enable or disable PDF exports |
| `CMD_CONFIG_FILE` | `/path/to/config.json` | optional override for the path to CodiMD's config file |
| `CMD_DB_URL` | `mysql://localhost:3306/database` | set the database URL |
| `CMD_DB_URL` | `mysql://localhost:3306/database` | Set the db in URL style. If set, then the relevant `db` config entries will be overridden. |
| `CMD_LOGLEVEL` | `info`, `debug` ... | Defines what kind of logs are provided to stdout. |
| `CMD_FORBIDDEN_NOTE_IDS` | `'robots.txt'` | disallow creation of notes, even if `CMD_ALLOW_FREEURL` is `true` |
| `CMD_IMAGE_UPLOAD_TYPE` | `imgur`, `s3`, `minio`, `lutim` or `filesystem` | Where to upload images. For S3, see our Image Upload Guides for [S3](guides/s3-image-upload.md) or [Minio](guides/minio-image-upload.md), also there's a whole section on their respective env vars below. |
| `CMD_SOURCE_URL` | `https://github.com/codimd/server/tree/<current commit>` | Provides the link to the source code of CodiMD on the entry page (Please, make sure you change this when you run a modified version) |
| `CMD_TOOBUSY_LAG` | `70` | CPU time for one eventloop tick until node throttles connections. (milliseconds) |
| `CMD_TOOBUSY_LAG` | `70` | CPU time for one event loop tick until node throttles connections. (milliseconds) |
## CodiMD Location
......@@ -76,11 +76,11 @@ defaultNotePath can't be set from env-vars
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_ALLOW_ANONYMOUS` | `true` or `false` | set to allow anonymous usage (default is `true`) |
| `CMD_ALLOW_ANONYMOUS_EDITS` | `true` or `false` | if `allowAnonymous` is `true`, allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`) |
| `CMD_ALLOW_FREEURL` | `true` or `false` | set to allow new note creation by accessing a nonexistent note URL |
| `CMD_DEFAULT_PERMISSION` | `freely`, `editable`, `limited`, `locked` or `private` | set notes default permission (only applied on signed users) |
| `CMD_SESSION_LIFE` | `1209600000` | Session life time. (milliseconds) |
| `CMD_ALLOW_ANONYMOUS` | `true` or `false` | Set to allow anonymous usage (default is `true`). |
| `CMD_ALLOW_ANONYMOUS_EDITS` | `true` or `false` | If `allowAnonymous` is `true`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`). |
| `CMD_ALLOW_FREEURL` | `true` or `false` | Set to allow new note creation by accessing a nonexistent note URL. This is the behavior familiar from [Etherpad](https://github.com/ether/etherpad-lite). |
| `CMD_DEFAULT_PERMISSION` | `freely`, `editable`, `limited`, `locked`, `protected` or `private` | Set notes default permission (only applied on signed-in users). |
| `CMD_SESSION_LIFE` | `1209600000` (14 days) | Cookie session life time in milliseconds. |
| `CMD_SESSION_SECRET` | no example | Secret used to sign the session cookie. If none is set, one will randomly generated on each startup, meaning all your users will be logged out. |
......@@ -90,8 +90,8 @@ defaultNotePath can't be set from env-vars
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_EMAIL` | `true` or `false` | set to allow email signin |
| `CMD_ALLOW_EMAIL_REGISTER` | `true` or `false` | set to allow email register (only applied when email is set, default is `true`. Note `bin/manage_users` might help you if registration is `false`.) |
| `CMD_EMAIL` | `true` or `false` | Set to allow email sign-in. The default is `true`. |
| `CMD_ALLOW_EMAIL_REGISTER` | `true` or `false` | Set to allow registration of new accounts using an email address. If set to `false`, you can still create accounts using the command line - see `bin/manage_users` for details. This setting has no effect if `CMD_EMAIL` is `false`. The default for `CMD_ALLOW_EMAIL_REGISTER` is `true`. |
### Dropbox Login
......@@ -166,7 +166,7 @@ defaultNotePath can't be set from env-vars
| variable | example value | description |
| -------- | ------------- | ----------- |
| `CMD_OAUTH2_USER_PROFILE_URL` | `https://example.com` | where retrieve information about a user after succesful login. Needs to output JSON. (no default value) Refer to the [Mattermost](guides/auth/mattermost-self-hosted.md) or [Nextcloud](guides/auth/nextcloud.md) examples for more details on all of the `CMD_OAUTH2...` options. |
| `CMD_OAUTH2_USER_PROFILE_URL` | `https://example.com` | Where to retrieve information about a user after successful login. Needs to output JSON. (no default value) Refer to the [Mattermost](guides/auth/mattermost-self-hosted.md) or [Nextcloud](guides/auth/nextcloud.md) examples for more details on all of the `CMD_OAUTH2...` options. |
| `CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR` | `name` | where to find the username in the JSON from the user profile URL. (no default value)|
| `CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR` | `display-name` | where to find the display-name in the JSON from the user profile URL. (no default value) |
| `CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR` | `email` | where to find the email address in the JSON from the user profile URL. (no default value) |
......@@ -183,7 +183,7 @@ defaultNotePath can't be set from env-vars
| -------- | ------------- | ----------- |
| `CMD_SAML_IDPSSOURL` | `https://idp.example.com/sso` | authentication endpoint of IdP. for details, see [guide](guides/auth/saml-onelogin.md). |
| `CMD_SAML_IDPCERT` | `/path/to/cert.pem` | certificate file path of IdP in PEM format |
| `CMD_SAML_ISSUER` | no example | identity of the service provider (optional, default: serverurl)" |
| `CMD_SAML_ISSUER` | no example | Issuer to supply to identity provider (optional, default: `serverURL` config)" |
| `CMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT` | `true` or `false` | true to allow any authentication method, false restricts to password authentication (PasswordProtectedTransport) method (default: false) |
| `CMD_SAML_IDENTIFIERFORMAT` | no example | name identifier format (optional, default: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`) |
| `CMD_SAML_GROUPATTRIBUTE` | `memberOf` | attribute name for group list (optional) |
......
Migrations and Notable Changes
===
## Migrating to 1.4.0
We dropped support for node 6 with this version. If you have any trouble running this version, please double check that you are running at least node 8!
## Migrating to 1.3.2
This is not a breaking change, but to stay up to date with the community
......
......@@ -15,3 +15,12 @@ To add a privacy policy you can use the same technique as for the terms of use.
See our example file `./public/docs/privacy.md.example` container some useful hints for writing your own privacy policy.
As with the terms of use, a link to the privacy notices will show up in the area where the release notes are provided on the index page.
Setup your imprint
===
To add an imprint you can use the same technique as for the terms of use. The main difference is that the document is called `imprint.md`.
It has to be provided under `./public/docs/` and will be automatically turned into a CodiMD document. It will also automatically updated as soon as you change the document on disk.
As with the terms of use, a link to the imprint will show up in the area where the release notes are provided on the index page.
LinuxServer.io CodiMD Image
===
[![LinuxServer.io Discord](https://img.shields.io/discord/354974912613449730.svg?logo=discord&label=LSIO%20Discord&style=flat-square)](https://discord.gg/YWrKVTn)[![container version badge](https://images.microbadger.com/badges/version/linuxserver/codimd.svg)](https://microbadger.com/images/linuxserver/codimd "Get your own version badge on microbadger.com")[![container image size badge](https://images.microbadger.com/badges/image/linuxserver/codimd.svg)](https://microbadger.com/images/linuxserver/codimd "Get your own version badge on microbadger.com")![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/codimd.svg)![Docker Stars](https://img.shields.io/docker/stars/linuxserver/codimd.svg)[![Build Status](https://ci.linuxserver.io/buildStatus/icon?job=Docker-Pipeline-Builders/docker-codimd/master)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-codimd/job/master/)[![LinuxServer.io CI summary](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/codimd/latest/badge.svg)](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/codimd/latest/index.html)
[LinuxServer.io](https://linuxserver.io) have created an Ubuntu-based multi-arch container image for x86-64, arm64 and armhf which supports PDF export from all architectures using [PhantomJS](https://phantomjs.org/).
- It supports all the environment variables detailed in the [configuration documentation](../configuration-env-vars.md) to modify it according to your needs.
- It gets rebuilt on new releases from CodiMD and also weekly if necessary to update any other package changes in the underlying container, making it easy to keep your CodiMD instance up to date.
- It also details how to easily [utilize Docker networking to reverse proxy](https://github.com/linuxserver/docker-codimd/#application-setup) CodiMD using their [LetsEncrypt docker image](https://github.com/linuxserver/docker-letsencrypt)
In order to contribute check the LinuxServer.io [GitHub repository](https://github.com/linuxserver/docker-codimd/) for CodiMD.
And to find all tags and versions of the image, check the [Docker Hub repository](https://hub.docker.com/r/linuxserver/codimd).
CodiMD by docker container
CodiMD Docker Image
===
[![Try in PWD](https://cdn.rawgit.com/play-with-docker/stacks/cff22438/assets/images/button.png)](http://play-with-docker.com?stack=https://github.com/codimd/container/raw/master/docker-compose.yml&stack_name=codimd)
......
......@@ -3,7 +3,7 @@
const fs = require('fs')
const path = require('path')
const basePath = path.resolve('/var/run/secrets/')
const basePath = path.resolve('/run/secrets/')
function getSecret (secret) {
const filePath = path.join(basePath, secret)
......@@ -13,11 +13,12 @@ function getSecret (secret) {
if (fs.existsSync(basePath)) {
module.exports = {
sessionsecret: getSecret('sessionsecret'),
sslkeypath: getSecret('sslkeypath'),
sslcertpath: getSecret('sslcertpath'),
sslcapath: getSecret('sslcapath'),
dhparampath: getSecret('dhparampath'),
dbURL: getSecret('dbURL'),
sessionSecret: getSecret('sessionsecret'),
sslKeyPath: getSecret('sslkeypath'),
sslCertPath: getSecret('sslcertpath'),
sslCAPath: getSecret('sslcapath'),
dhParamPath: getSecret('dhparampath'),
s3: {
accessKeyId: getSecret('s3_acccessKeyId'),
secretAccessKey: getSecret('s3_secretAccessKey')
......
'use strict'
const {toBooleanConfig, toArrayConfig, toIntegerConfig} = require('./utils')
const { toBooleanConfig, toArrayConfig, toIntegerConfig } = require('./utils')
module.exports = {
sourceURL: process.env.CMD_SOURCE_URL,
......@@ -41,7 +41,8 @@ module.exports = {
s3: {
accessKeyId: process.env.CMD_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.CMD_S3_SECRET_ACCESS_KEY,
region: process.env.CMD_S3_REGION
region: process.env.CMD_S3_REGION,
endpoint: process.env.CMD_S3_ENDPOINT
},
minio: {
accessKey: process.env.CMD_MINIO_ACCESS_KEY,
......
'use strict'
const {toBooleanConfig, toArrayConfig, toIntegerConfig} = require('./utils')
const { toBooleanConfig, toArrayConfig, toIntegerConfig } = require('./utils')
module.exports = {
domain: process.env.HMD_DOMAIN,
......
......@@ -4,11 +4,11 @@
const crypto = require('crypto')
const fs = require('fs')
const path = require('path')
const {merge} = require('lodash')
const { merge } = require('lodash')
const deepFreeze = require('deep-freeze')
const {Environment, Permission} = require('./enum')
const { Environment, Permission } = require('./enum')
const logger = require('../logger')
const {getGitCommit, getGitHubURL} = require('./utils')
const { getGitCommit, getGitHubURL } = require('./utils')
const appRootPath = path.resolve(__dirname, '../../')
const env = process.env.NODE_ENV || Environment.development
......@@ -17,7 +17,7 @@ const debugConfig = {
}
// Get version string from package.json
const {version, repository} = require(path.join(appRootPath, 'package.json'))
const { version, repository } = require(path.join(appRootPath, 'package.json'))
const commitID = getGitCommit(appRootPath)
const sourceURL = getGitHubURL(repository.url, commitID || version)
......@@ -159,8 +159,8 @@ if (Object.keys(process.env).toString().indexOf('HMD_') !== -1) {
if (config.sessionSecret === 'secret') {
logger.warn('Session secret not set. Using random generated one. Please set `sessionSecret` in your config.js file. All users will be logged out.')
config.sessionSecret = crypto.randomBytes(Math.ceil(config.sessionSecretLen / 2)) // generate crypto graphic random number
.toString('hex') // convert to hexadecimal format
.slice(0, config.sessionSecretLen) // return required number of characters
.toString('hex') // convert to hexadecimal format
.slice(0, config.sessionSecretLen) // return required number of characters
}
// Validate upload upload providers
......@@ -189,6 +189,12 @@ switch (config.imageUploadType) {
]
}
// Disable PDF export due to security issue
if (config.allowPDFExport) {
config.allowPDFExport = false
logger.warn('PDF export was disabled for this release to mitigate a critical security issue. This feature will hopefully become available again in future releases.')
}
// generate correct path
config.sslCAPath.forEach(function (capath, i, array) {
array[i] = path.resolve(appRootPath, capath)
......
'use strict'
const {toBooleanConfig} = require('./utils')
const { toBooleanConfig } = require('./utils')
module.exports = {
debug: toBooleanConfig(process.env.DEBUG),
......
......@@ -4,7 +4,6 @@
var LZString = require('lz-string')
// core
var config = require('./config')
var logger = require('./logger')
var response = require('./response')
var models = require('./models')
......@@ -56,9 +55,7 @@ function getHistory (userid, callback) {
}
history = parseHistoryToObject(history)
}
if (config.debug) {
logger.info('read history success: ' + user.id)
}
logger.debug(`read history success: ${user.id}`)
return callback(null, history)
}).catch(function (err) {
logger.error('read history failed: ' + err)
......@@ -140,7 +137,7 @@ function historyPost (req, res) {
var noteId = req.params.noteId
if (!noteId) {
if (typeof req.body['history'] === 'undefined') return response.errorBadRequest(res)
if (config.debug) { logger.info('SERVER received history from [' + req.user.id + ']: ' + req.body.history) }
logger.debug(`SERVER received history from [${req.user.id}]: ${req.body.history}`)
try {
var history = JSON.parse(req.body.history)
} catch (err) {
......
......@@ -30,14 +30,14 @@ exports.generateAvatarURL = function (name, email = '', big = true) {
if (typeof email !== 'string') {
email = '' + name + '@example.com'
}
name=encodeURIComponent(name)
name = encodeURIComponent(name)
let hash = crypto.createHash('md5')
hash.update(email.toLowerCase())
let hexDigest = hash.digest('hex')
if (email !== '' && config.allowGravatar) {
photo = 'https://cdn.libravatar.org/avatar/' + hexDigest;
photo = 'https://cdn.libravatar.org/avatar/' + hexDigest
if (big) {
photo += '?s=400'
} else {
......
'use strict'
const {createLogger, format, transports} = require('winston')
const { createLogger, format, transports } = require('winston')
const logger = createLogger({
level: 'debug',
......
......@@ -22,6 +22,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: shortid' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'shortid'" || error.message === 'column "shortid" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -9,6 +9,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: lastchangeuserId' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'lastchangeuserId'" || error.message === 'column "lastchangeuserId" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......@@ -18,8 +19,8 @@ module.exports = {
down: function (queryInterface, Sequelize) {
return queryInterface.removeColumn('Notes', 'lastchangeAt')
.then(function () {
return queryInterface.removeColumn('Notes', 'lastchangeuserId')
})
.then(function () {
return queryInterface.removeColumn('Notes', 'lastchangeuserId')
})
}
}
......@@ -9,6 +9,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: alias' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'alias'" || error.message === 'column "alias" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -5,6 +5,7 @@ module.exports = {
return queryInterface.addColumn('Users', 'refreshToken', Sequelize.STRING)
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: accessToken' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'accessToken'" || error.message === 'column "accessToken" of relation "Users" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -17,6 +17,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: savedAt' | error.message === "ER_DUP_FIELDNAME: Duplicate column name 'savedAt'" || error.message === 'column "savedAt" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -18,6 +18,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: authorship' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'authorship'" || error.message === 'column "authorship" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -3,6 +3,7 @@ module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.addColumn('Notes', 'deletedAt', Sequelize.DATE).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: deletedAt' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'deletedAt'" || error.message === 'column "deletedAt" of relation "Notes" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
......@@ -4,6 +4,7 @@ module.exports = {
return queryInterface.addColumn('Users', 'email', Sequelize.TEXT).then(function () {
return queryInterface.addColumn('Users', 'password', Sequelize.TEXT).catch(function (error) {
if (error.message === "ER_DUP_FIELDNAME: Duplicate column name 'password'" || error.message === 'column "password" of relation "Users" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......@@ -11,6 +12,7 @@ module.exports = {
})
}).catch(function (error) {
if (error.message === 'SQLITE_ERROR: duplicate column name: email' || error.message === "ER_DUP_FIELDNAME: Duplicate column name 'email'" || error.message === 'column "email" of relation "Users" already exists') {
// eslint-disable-next-line no-console
console.log('Migration has already run… ignoring.')
} else {
throw error
......
'use strict'
module.exports = {
up: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'content', {type: Sequelize.TEXT('long')})
queryInterface.changeColumn('Revisions', 'patch', {type: Sequelize.TEXT('long')})
queryInterface.changeColumn('Revisions', 'content', {type: Sequelize.TEXT('long')})
queryInterface.changeColumn('Revisions', 'lastContent', {type: Sequelize.TEXT('long')})
up: async function (queryInterface, Sequelize) {
await queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT('long') })
await queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT('long') })
await queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT('long') })
await queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT('long') })
},
down: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'content', {type: Sequelize.TEXT})
queryInterface.changeColumn('Revisions', 'patch', {type: Sequelize.TEXT})
queryInterface.changeColumn('Revisions', 'content', {type: Sequelize.TEXT})
queryInterface.changeColumn('Revisions', 'lastContent', {type: Sequelize.TEXT})
down: async function (queryInterface, Sequelize) {
await queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT })
await queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT })
await queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT })
await queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT })
}
}
'use strict'
module.exports = {
up: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'authorship', {type: Sequelize.TEXT('long')})
queryInterface.changeColumn('Revisions', 'authorship', {type: Sequelize.TEXT('long')})
up: async function (queryInterface, Sequelize) {
await queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT('long') })
await queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT('long') })
},
down: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'authorship', {type: Sequelize.TEXT})
queryInterface.changeColumn('Revisions', 'authorship', {type: Sequelize.TEXT})
down: async function (queryInterface, Sequelize) {
await queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT })
await queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT })
}
}
......@@ -2,10 +2,10 @@
module.exports = {
up: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'permission', {type: Sequelize.ENUM('freely', 'editable', 'limited', 'locked', 'protected', 'private')})
return queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'limited', 'locked', 'protected', 'private') })
},
down: function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'permission', {type: Sequelize.ENUM('freely', 'editable', 'locked', 'private')})
return queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'locked', 'private') })
}
}
......@@ -18,25 +18,25 @@ module.exports = function (sequelize, DataTypes) {
unique: true,
fields: ['noteId', 'userId']
}
],
classMethods: {
associate: function (models) {
Author.belongsTo(models.Note, {
foreignKey: 'noteId',
as: 'note',
constraints: false,
onDelete: 'CASCADE',
hooks: true
})
Author.belongsTo(models.User, {
foreignKey: 'userId',
as: 'user',
constraints: false,
onDelete: 'CASCADE',
hooks: true