Unverified Commit e29422fa authored by Yukai Huang's avatar Yukai Huang Committed by GitHub
Browse files

Merge pull request #1477 from hackmdio/release/2.0.1

Release 2.0.1
parents 16b9409e e07884cc
...@@ -15,6 +15,7 @@ Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and contr ...@@ -15,6 +15,7 @@ Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and contr
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
# Table of Contents # Table of Contents
- [HackMD](#hackmd)
- [CodiMD - The Open Source HackMD](#codimd---the-open-source-hackmd) - [CodiMD - The Open Source HackMD](#codimd---the-open-source-hackmd)
- [Documentation](#documentation) - [Documentation](#documentation)
- [Deployment](#deployment) - [Deployment](#deployment)
...@@ -27,14 +28,17 @@ Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and contr ...@@ -27,14 +28,17 @@ Built on [HackMD](https://hackmd.io) source code, CodiMD lets you host and contr
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
## CodiMD - The Open Source HackMD ## HackMD
[HackMD](https://hackmd.io) helps developers write better documents and build active communities with open collaboration. [HackMD](https://hackmd.io) helps developers write better documents and build active communities with open collaboration.
HackMD is built with one promise - **You own and control all your content**: HackMD is built with one promise - **You own and control all your content**:
- You should be able to easily [download all your online content at once](https://hackmd.io/c/news/%2Fs%2Fr1cx3a3SE). - You should be able to easily [download all your online content at once](https://hackmd.io/c/news/%2Fs%2Fr1cx3a3SE).
- Your content formatting should be portable as well. (That's why we choose [markdown](https://hackmd.io/features#Typography).) - Your content formatting should be portable as well. (That's why we choose [markdown](https://hackmd.io/features#Typography).)
- You should be able to control your content's presentation with HTML, [slide mode](https://hackmd.io/p/slide-example), or [book mode](https://hackmd.io/c/book-example/). - You should be able to control your content's presentation with HTML, [slide mode](https://hackmd.io/p/slide-example), or [book mode](https://hackmd.io/c/book-example/).
With the same promise of you owning your content, CodiMD is the free software version of [HackMD](https://hackmd.io), developed and opened source by the HackMD team with reduced features, so you can use CodiMD for your community and own your data. *(See the [origin of the name CodiMD](https://github.com/hackmdio/hackmd/issues/720).)* ## CodiMD - The Open Source HackMD
CodiMD is the free software version of [HackMD](https://hackmd.io), developed and opened source by the HackMD team with reduced features (without book mode), you can use CodiMD for your community and own all your data. *(See the [origin of the name CodiMD](https://github.com/hackmdio/hackmd/issues/720).)*
CodiMD is perfect for open communities, while HackMD emphasizes on permission and access controls for commercial use cases. CodiMD is perfect for open communities, while HackMD emphasizes on permission and access controls for commercial use cases.
......
...@@ -7,6 +7,7 @@ function parseProfile (data) { ...@@ -7,6 +7,7 @@ function parseProfile (data) {
const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr) const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr)
const displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr) const displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr)
const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr) const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr)
const photo = extractProfileAttribute(data, config.oauth2.userProfilePhotoAttr)
if (!username) { if (!username) {
throw new Error('cannot fetch username: please set correct CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR') throw new Error('cannot fetch username: please set correct CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR')
...@@ -16,7 +17,8 @@ function parseProfile (data) { ...@@ -16,7 +17,8 @@ function parseProfile (data) {
id: username, id: username,
username: username, username: username,
displayName: displayName, displayName: displayName,
email: email email: email,
photo: photo
} }
} }
......
...@@ -99,6 +99,7 @@ module.exports = { ...@@ -99,6 +99,7 @@ module.exports = {
userProfileUsernameAttr: 'username', userProfileUsernameAttr: 'username',
userProfileDisplayNameAttr: 'displayName', userProfileDisplayNameAttr: 'displayName',
userProfileEmailAttr: 'email', userProfileEmailAttr: 'email',
userProfilePhotoAttr: 'photo',
scope: 'email' scope: 'email'
}, },
facebook: { facebook: {
......
...@@ -13,18 +13,32 @@ function getSecret (secret) { ...@@ -13,18 +13,32 @@ function getSecret (secret) {
if (fs.existsSync(basePath)) { if (fs.existsSync(basePath)) {
module.exports = { module.exports = {
sessionsecret: getSecret('sessionsecret'), dbURL: getSecret('dburl'),
sslkeypath: getSecret('sslkeypath'), // ssl path
sslcertpath: getSecret('sslcertpath'), sslKeyPath: getSecret('sslkeypath'),
sslcapath: getSecret('sslcapath'), sslCertPath: getSecret('sslcertpath'),
dhparampath: getSecret('dhparampath'), sslCAPath: getSecret('sslcapath'),
dhParamPath: getSecret('dhparampath'),
// session
sessionSecret: getSecret('sessionsecret'),
imgur: {
clientID: getSecret('imgur_clientid')
},
s3: { s3: {
accessKeyId: getSecret('s3_acccessKeyId'), accessKeyId: getSecret('s3_acccessKeyId'),
secretAccessKey: getSecret('s3_secretAccessKey') secretAccessKey: getSecret('s3_secretAccessKey')
}, },
minio: {
accessKey: getSecret('minio_accessKey'),
secretKey: getSecret('minio_secretKey')
},
azure: { azure: {
connectionString: getSecret('azure_connectionString') connectionString: getSecret('azure_connectionString')
}, },
oauth2: {
clientID: getSecret('oauth2_clientID'),
clientSecret: getSecret('oauth2_clientSecret')
},
facebook: { facebook: {
clientID: getSecret('facebook_clientID'), clientID: getSecret('facebook_clientID'),
clientSecret: getSecret('facebook_clientSecret') clientSecret: getSecret('facebook_clientSecret')
...@@ -54,6 +68,12 @@ if (fs.existsSync(basePath)) { ...@@ -54,6 +68,12 @@ if (fs.existsSync(basePath)) {
clientID: getSecret('google_clientID'), clientID: getSecret('google_clientID'),
clientSecret: getSecret('google_clientSecret') clientSecret: getSecret('google_clientSecret')
}, },
imgur: getSecret('imgur_clientid') ldap: {
bindCredentials: getSecret('ldap_bindCredentials'),
tlsca: getSecret('ldap_tlsca')
},
saml: {
idpCert: getSecret('saml_idpCert')
}
} }
} }
...@@ -96,7 +96,8 @@ module.exports = { ...@@ -96,7 +96,8 @@ module.exports = {
scope: process.env.CMD_OAUTH2_SCOPE, scope: process.env.CMD_OAUTH2_SCOPE,
userProfileUsernameAttr: process.env.CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR, userProfileUsernameAttr: process.env.CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR,
userProfileDisplayNameAttr: process.env.CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR, userProfileDisplayNameAttr: process.env.CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR,
userProfileEmailAttr: process.env.CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR userProfileEmailAttr: process.env.CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR,
userProfilePhotoAttr: process.env.CMD_OAUTH2_USER_PROFILE_PHOTO_ATTR
}, },
dropbox: { dropbox: {
clientID: process.env.CMD_DROPBOX_CLIENTID, clientID: process.env.CMD_DROPBOX_CLIENTID,
......
...@@ -6,7 +6,7 @@ const config = require('../config') ...@@ -6,7 +6,7 @@ const config = require('../config')
const { getImageMimeType } = require('../utils') const { getImageMimeType } = require('../utils')
const logger = require('../logger') const logger = require('../logger')
const Minio = require('lib/imageRouter/minio') const Minio = require('minio')
const minioClient = new Minio.Client({ const minioClient = new Minio.Client({
endPoint: config.minio.endPoint, endPoint: config.minio.endPoint,
port: config.minio.port, port: config.minio.port,
......
...@@ -140,6 +140,10 @@ module.exports = function (sequelize, DataTypes) { ...@@ -140,6 +140,10 @@ module.exports = function (sequelize, DataTypes) {
case 'saml': case 'saml':
photo = generateAvatarURL(profile.username, profile.emails[0], bigger) photo = generateAvatarURL(profile.username, profile.emails[0], bigger)
break break
case 'oauth2':
photo = profile.photo
if (!photo) photo = generateAvatarURL(profile.username, profile.email, bigger)
break
} }
return photo return photo
} }
......
...@@ -34,7 +34,7 @@ async function getNoteById (noteId, { includeUser } = { includeUser: false }) { ...@@ -34,7 +34,7 @@ async function getNoteById (noteId, { includeUser } = { includeUser: false }) {
} }
async function createNote (userId, noteAlias) { async function createNote (userId, noteAlias) {
if (!config.allowAnonymous && !!userId) { if (!config.allowAnonymous && !userId) {
throw new Error('can not create note') throw new Error('can not create note')
} }
......
...@@ -30,11 +30,12 @@ async function checkVersion (ctx) { ...@@ -30,11 +30,12 @@ async function checkVersion (ctx) {
const { statusCode, body: data } = await rp({ const { statusCode, body: data } = await rp({
url: `${VERSION_CHECK_ENDPOINT}?v=${config.version}`, url: `${VERSION_CHECK_ENDPOINT}?v=${config.version}`,
method: 'GET', method: 'GET',
json: true json: true,
timeout: 3000
}) })
if (statusCode !== 200 || data.status === 'error') { if (statusCode !== 200 || data.status === 'error') {
logger.error('Version check failed.') logger.warn('Version check failed.')
return return
} }
...@@ -46,12 +47,12 @@ async function checkVersion (ctx) { ...@@ -46,12 +47,12 @@ async function checkVersion (ctx) {
if (!data.latest) { if (!data.latest) {
const { version, link } = data.versionItem const { version, link } = data.versionItem
logger.warn(`Your CodiMD version is out of date! The latest version is ${version}. Please see what's new on ${link}.`) logger.info(`Your CodiMD version is out of date! The latest version is ${version}. Please see what's new on ${link}.`)
} }
} catch (err) { } catch (err) {
// ignore and skip version check // ignore and skip version check
logger.error('Version check failed.') logger.warn('Version check failed.')
logger.error(err) logger.warn(err)
} }
} }
......
...@@ -385,12 +385,26 @@ ...@@ -385,12 +385,26 @@
"integrity": "sha512-yuv9BBdA5rk4TpmSrsdNgkLIyRt73hWyBEs7PhWhIozFcNv66JfUzXqA0eT3ToXX0163aVnbpHeJZRvcYy5Seg==" "integrity": "sha512-yuv9BBdA5rk4TpmSrsdNgkLIyRt73hWyBEs7PhWhIozFcNv66JfUzXqA0eT3ToXX0163aVnbpHeJZRvcYy5Seg=="
}, },
"@hackmd/imgur": { "@hackmd/imgur": {
"version": "0.4.1", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/@hackmd/imgur/-/imgur-0.4.1.tgz", "resolved": "https://registry.npmjs.org/@hackmd/imgur/-/imgur-0.5.0.tgz",
"integrity": "sha512-zvAt/4drM+nZG/yM12hJ7/DtkPffw/fzvr8oDp6twg5a04/HBoGha28vYrZP4fV/a5ZAAnRzxRRbeADxRfsGfA==", "integrity": "sha512-5WygmZ0LEezFMxlxxuT03Y9ZNtbJU2ECHTi1Mc2m7SPeUG6sfU3vGsQKmooWA6f5F7HLVskuaSVVq9mOMQv5jg==",
"requires": { "requires": {
"glob": "^7.1.3", "commander": "^2.13.0",
"request": "^2.88.0" "glob": "^7.1.2",
"q": "^2.0.3",
"request": "^2.83.0"
},
"dependencies": {
"q": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",
"integrity": "sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ=",
"requires": {
"asap": "^2.0.0",
"pop-iterate": "^1.0.1",
"weak-map": "^1.0.5"
}
}
} }
}, },
"@hackmd/js-sequence-diagrams": { "@hackmd/js-sequence-diagrams": {
...@@ -1228,9 +1242,7 @@ ...@@ -1228,9 +1242,7 @@
"asap": { "asap": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
"dev": true,
"optional": true
}, },
"asn1": { "asn1": {
"version": "0.2.4", "version": "0.2.4",
...@@ -11615,6 +11627,11 @@ ...@@ -11615,6 +11627,11 @@
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
}, },
"pop-iterate": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz",
"integrity": "sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M="
},
"posix-character-classes": { "posix-character-classes": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
...@@ -16489,6 +16506,11 @@ ...@@ -16489,6 +16506,11 @@
"typechecker": "^2.0.8" "typechecker": "^2.0.8"
} }
}, },
"weak-map": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz",
"integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes="
},
"webidl-conversions": { "webidl-conversions": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
......
{ {
"name": "codimd", "name": "codimd",
"version": "2.0.0", "version": "2.0.1",
"description": "Realtime collaborative markdown notes on all platforms.", "description": "Realtime collaborative markdown notes on all platforms.",
"keywords": [ "keywords": [
"Collaborative", "Collaborative",
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
"@hackmd/codemirror": "~5.49.5", "@hackmd/codemirror": "~5.49.5",
"@hackmd/diff-match-patch": "~1.1.3", "@hackmd/diff-match-patch": "~1.1.3",
"@hackmd/idle-js": "~1.0.1", "@hackmd/idle-js": "~1.0.1",
"@hackmd/imgur": "~0.4.1", "@hackmd/imgur": "~0.5.0",
"@hackmd/js-sequence-diagrams": "~0.0.1-alpha.3", "@hackmd/js-sequence-diagrams": "~0.0.1-alpha.3",
"@hackmd/lz-string": "~1.4.4", "@hackmd/lz-string": "~1.4.4",
"@hackmd/meta-marked": "~0.4.4", "@hackmd/meta-marked": "~0.4.4",
......
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
} }
.ui-toc-label { .ui-toc-label {
opacity: 0.3; opacity: 0.9;
background-color: #ccc; background-color: #ccc;
border: none; border: none;
-webkit-transition: opacity 0.2s; /* Safari */ -webkit-transition: opacity 0.2s; /* Safari */
...@@ -117,13 +117,13 @@ ...@@ -117,13 +117,13 @@
.ui-toc .open .ui-toc-label { .ui-toc .open .ui-toc-label {
opacity: 1; opacity: 1;
color: white; color: #5f5f5f;
-webkit-transition: opacity 0.2s; /* Safari */ -webkit-transition: opacity 0.2s; /* Safari */
transition: opacity 0.2s; transition: opacity 0.2s;
} }
.ui-toc-label:focus { .ui-toc-label:focus {
opacity: 0.3; opacity: 1;
background-color: #ccc; background-color: #ccc;
color: black; color: black;
} }
...@@ -326,7 +326,7 @@ ...@@ -326,7 +326,7 @@
margin-left: 10px; margin-left: 10px;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: #999; color: rgba(0, 0, 0, 0.85);
} }
.expand-toggle:hover, .expand-toggle:focus, .back-to-top:hover, .back-to-top:focus, .go-to-bottom:hover, .go-to-bottom:focus { .expand-toggle:hover, .expand-toggle:focus, .back-to-top:hover, .back-to-top:focus, .go-to-bottom:hover, .go-to-bottom:focus {
......
...@@ -570,7 +570,7 @@ div[contenteditable]:empty:not(:focus):before{ ...@@ -570,7 +570,7 @@ div[contenteditable]:empty:not(:focus):before{
.ui-theme-toggle, .ui-theme-toggle,
.ui-linter-toggle, .ui-linter-toggle,
.ui-spellcheck-toggle { .ui-spellcheck-toggle {
opacity: 0.2; opacity: 0.5;
cursor: pointer; cursor: pointer;
} }
......
Release Notes Release Notes
=== ===
<i class="fa fa-tag"></i> 2.0.1 Urocissa caerulea <i class="fa fa-clock-o"></i> 2020-04-09
---
[CodiMD 2.0.1](https://github.com/hackmdio/codimd/releases/tag/2.0.1) is a minor release fixing bugs introduced in 2.0.0 and earlier versions along with some enhancements. We encourage everyone to upgrade to 2.0.1 now. See how things are going on [GitHub](https://github.com/hackmdio/codimd/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc+milestone%3ANext). Stay tuned and healthy, and we hope you love it!
### Enhancements
- Allow inline markdown in spoiler summary syntax
- Improve visibility of some UI elements
- Support avatar for OAuth users
### Fixes
- Fix to add missing configs in docker secret
- Fix not able to upload image using imgur
- Fix to improve version checker behavior
- Fix Wikipedia link in 2.0.0 release notes
- Fix require path for minio
- Fix check for creating free url notes
[Check out the complete release note][v2_0_1]. Thank you CodiMD community and all our contributors. ❤️
[v2_0_1]: https://hackmd.io/@codimd/release-notes/%2F%40codimd%2Fv2_0_1
<i class="fa fa-tag"></i> 2.0.0 Urocissa caerulea <i class="fa fa-clock-o"></i> 2020-03-02 <i class="fa fa-tag"></i> 2.0.0 Urocissa caerulea <i class="fa fa-clock-o"></i> 2020-03-02
--- ---
...@@ -11,7 +36,7 @@ Release Notes ...@@ -11,7 +36,7 @@ Release Notes
> The Taiwan blue magpie (Urocissa caerulea), also called the Taiwan magpie, Formosan blue magpie , or the "long-tailed mountain lady", is a species of bird of the crow family. It is endemic to Taiwan. > The Taiwan blue magpie (Urocissa caerulea), also called the Taiwan magpie, Formosan blue magpie , or the "long-tailed mountain lady", is a species of bird of the crow family. It is endemic to Taiwan.
> >
> \- Wikipedia [Taiwan blue magpie](en.wikipedia.org/wiki/Taiwan_blue_magpie) > \- Wikipedia [Taiwan blue magpie](https://en.wikipedia.org/wiki/Taiwan_blue_magpie)
In the past few months, we delivered not only a bunch of awesome features but also some critical bug fixes. Moreover, we refactored CodiMD's backend and started to write new tests. In the past few months, we delivered not only a bunch of awesome features but also some critical bug fixes. Moreover, we refactored CodiMD's backend and started to write new tests.
......
...@@ -1124,7 +1124,7 @@ md.use(markdownitContainer, 'spoiler', { ...@@ -1124,7 +1124,7 @@ md.use(markdownitContainer, 'spoiler', {
// opening tag // opening tag
const summary = m[1] && m[1].trim() const summary = m[1] && m[1].trim()
if (summary) { if (summary) {
return `<details><summary>${md.utils.escapeHtml(summary)}</summary>\n` return `<details><summary>${md.renderInline(summary)}</summary>\n`
} else { } else {
return `<details>\n` return `<details>\n`
} }
......
...@@ -125,7 +125,7 @@ md.use(markdownitContainer, 'spoiler', { ...@@ -125,7 +125,7 @@ md.use(markdownitContainer, 'spoiler', {
const partClass = `class="part raw" data-startline="${startline}" data-endline="${endline}"` const partClass = `class="part raw" data-startline="${startline}" data-endline="${endline}"`
const summary = m[1] && m[1].trim() const summary = m[1] && m[1].trim()
if (summary) { if (summary) {
return `<details ${partClass}><summary>${md.utils.escapeHtml(summary)}</summary>\n` return `<details ${partClass}><summary>${md.renderInline(summary)}</summary>\n`
} else { } else {
return `<details ${partClass}>\n` return `<details ${partClass}>\n`
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment