Merge branch 'develop' into feature/slides-timer

This commit is contained in:
Raccoon 2019-06-27 17:34:47 +08:00 committed by GitHub
commit a338346261
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 81 additions and 55 deletions

View File

@ -76,6 +76,8 @@ To stay up to date with your installation it's recommended to subscribe the [rel
**License under AGPL.** **License under AGPL.**
[gitter-image]: https://img.shields.io/badge/gitter-hackmdio/codimd-blue.svg
[gitter-url]: https://gitter.im/hackmdio/hackmd
[travis-image]: https://travis-ci.org/hackmdio/codimd.svg?branch=master [travis-image]: https://travis-ci.org/hackmdio/codimd.svg?branch=master
[travis-url]: https://travis-ci.org/hackmdio/codimd [travis-url]: https://travis-ci.org/hackmdio/codimd
[github-version-badge]: https://img.shields.io/github/release/hackmdio/codimd.svg [github-version-badge]: https://img.shields.io/github/release/hackmdio/codimd.svg

View File

@ -66,7 +66,8 @@ module.exports = {
s3: { s3: {
accessKeyId: undefined, accessKeyId: undefined,
secretAccessKey: undefined, secretAccessKey: undefined,
region: undefined region: undefined,
endpoint: undefined
}, },
minio: { minio: {
accessKey: undefined, accessKey: undefined,

View File

@ -40,7 +40,8 @@ module.exports = {
s3: { s3: {
accessKeyId: process.env.CMD_S3_ACCESS_KEY_ID, accessKeyId: process.env.CMD_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.CMD_S3_SECRET_ACCESS_KEY, 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: { minio: {
accessKey: process.env.CMD_MINIO_ACCESS_KEY, accessKey: process.env.CMD_MINIO_ACCESS_KEY,

View File

@ -1,16 +1,16 @@
'use strict' 'use strict'
module.exports = { module.exports = {
up: function (queryInterface, Sequelize) { up: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT('long') })
queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT('long') })
queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT('long') })
queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT('long') })
}, },
down: function (queryInterface, Sequelize) { down: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Notes', 'content', { type: Sequelize.TEXT })
queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Revisions', 'patch', { type: Sequelize.TEXT })
queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Revisions', 'content', { type: Sequelize.TEXT })
queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Revisions', 'lastContent', { type: Sequelize.TEXT })
} }
} }

View File

@ -1,13 +1,13 @@
'use strict' 'use strict'
module.exports = { module.exports = {
up: function (queryInterface, Sequelize) { up: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT('long') })
queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT('long') }) await queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT('long') })
}, },
down: function (queryInterface, Sequelize) { down: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Notes', 'authorship', { type: Sequelize.TEXT })
queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT }) await queryInterface.changeColumn('Revisions', 'authorship', { type: Sequelize.TEXT })
} }
} }

View File

@ -1,11 +1,11 @@
'use strict' 'use strict'
module.exports = { module.exports = {
up: function (queryInterface, Sequelize) { up: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'limited', 'locked', 'protected', 'private') }) await queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'limited', 'locked', 'protected', 'private') })
}, },
down: function (queryInterface, Sequelize) { down: async function (queryInterface, Sequelize) {
queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'locked', 'private') }) await queryInterface.changeColumn('Notes', 'permission', { type: Sequelize.ENUM('freely', 'editable', 'locked', 'private') })
} }
} }

View File

@ -14,6 +14,7 @@ var config = require('./config')
var logger = require('./logger') var logger = require('./logger')
var models = require('./models') var models = require('./models')
var utils = require('./utils') var utils = require('./utils')
var history = require('./history')
// public // public
var response = { var response = {
@ -106,6 +107,12 @@ function responseCodiMD (res, note) {
}) })
} }
function updateHistory (userId, note, document, time) {
var noteId = note.alias ? note.alias : models.Note.encodeNoteId(note.id)
history.updateHistory(userId, noteId, document, time)
logger.info('history updated')
}
function newNote (req, res, next) { function newNote (req, res, next) {
var owner = null var owner = null
var body = '' var body = ''
@ -125,6 +132,10 @@ function newNote (req, res, next) {
alias: req.alias ? req.alias : null, alias: req.alias ? req.alias : null,
content: body content: body
}).then(function (note) { }).then(function (note) {
if (req.isAuthenticated()) {
updateHistory(owner, note, body)
}
return res.redirect(config.serverURL + '/' + models.Note.encodeNoteId(note.id)) return res.redirect(config.serverURL + '/' + models.Note.encodeNoteId(note.id))
}).catch(function (err) { }).catch(function (err) {
logger.error(err) logger.error(err)

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
require('babel-polyfill') require('babel-polyfill')
require('isomorphic-fetch'); require('isomorphic-fetch')
const Router = require('express').Router const Router = require('express').Router
const passport = require('passport') const passport = require('passport')
const MattermostClient = require('mattermost-redux/client/client4').default const MattermostClient = require('mattermost-redux/client/client4').default

View File

@ -16,5 +16,12 @@ exports.uploadImage = function (imagePath, callback) {
return return
} }
callback(null, (new URL(path.basename(imagePath), config.serverURL + '/uploads/')).href) let url
try {
url = (new URL(path.basename(imagePath), config.serverURL + '/uploads/')).href
} catch (e) {
url = config.serverURL + '/uploads/' + path.basename(imagePath)
}
callback(null, url)
} }

View File

@ -40,7 +40,9 @@ exports.uploadImage = function (imagePath, callback) {
callback(new Error(err), null) callback(new Error(err), null)
return return
} }
callback(null, `${protocol}://${config.minio.endPoint}:${config.minio.port}/${config.s3bucket}/${key}`) let hidePort = [80, 443].includes(config.minio.port)
let urlPort = hidePort ? '' : `:${config.minio.port}`
callback(null, `${protocol}://${config.minio.endPoint}${urlPort}/${config.s3bucket}/${key}`)
}) })
}) })
} }

View File

@ -42,7 +42,9 @@ exports.uploadImage = function (imagePath, callback) {
} }
let s3Endpoint = 's3.amazonaws.com' let s3Endpoint = 's3.amazonaws.com'
if (config.s3.region && config.s3.region !== 'us-east-1') { if (config.s3.endpoint) {
s3Endpoint = config.s3.endpoint
} else if (config.s3.region && config.s3.region !== 'us-east-1') {
s3Endpoint = `s3-${config.s3.region}.amazonaws.com` s3Endpoint = `s3-${config.s3.region}.amazonaws.com`
} }
callback(null, `https://${s3Endpoint}/${config.s3bucket}/${params.Key}`) callback(null, `https://${s3Endpoint}/${config.s3bucket}/${params.Key}`)

View File

@ -33,7 +33,7 @@ UserRouter.get('/me', function (req, res) {
return response.errorInternalError(res) return response.errorInternalError(res)
}) })
} else { } else {
res.send({ res.status(401).send({
status: 'forbidden' status: 'forbidden'
}) })
} }

View File

@ -1,42 +1,42 @@
{ {
"Collaborative markdown notes": "Markdown 協作筆記", "Collaborative markdown notes": "Markdown 協作筆記",
"Realtime collaborative markdown notes on all platforms.": "使用 Markdown 的跨平台即時協作筆記", "Realtime collaborative markdown notes on all platforms.": "使用 Markdown 的跨平台即時協作筆記",
"Best way to write and share your knowledge in markdown.": "使用 Markdown 寫作與分享知識的最佳方式", "Best way to write and share your knowledge in markdown.": "使用 Markdown 寫作與分享知識的最佳方式",
"Intro": "簡介", "Intro": "簡介",
"History": "錄", "History": "歷史記錄",
"New guest note": "建立訪客筆記", "New guest note": "建立訪客筆記",
"Collaborate with URL": "使用網址協作", "Collaborate with URL": "使用網址協作",
"Support charts and MathJax": "支援圖表與 MathJax", "Support charts and MathJax": "支援圖表與 MathJax",
"Support slide mode": "支援簡報模式", "Support slide mode": "支援簡報模式",
"Sign In": "登入", "Sign In": "登入",
"Below is the history from browser": "以下為來自瀏覽器的紀錄", "Below is the history from browser": "以下是從瀏覽器取得的歷史記錄",
"Welcome!": "歡迎!", "Welcome!": "歡迎!",
"New note": "建立筆記", "New note": "建立筆記",
"or": "或", "or": "或",
"Sign Out": "登出", "Sign Out": "登出",
"Explore all features": "探索所有功能", "Explore all features": "探索所有功能",
"Select tags...": "選擇標籤...", "Select tags...": "選擇標籤",
"Search keyword...": "搜尋關鍵字...", "Search keyword...": "搜尋關鍵字",
"Sort by title": "標題排序", "Sort by title": "標題排序",
"Title": "標題", "Title": "標題",
"Sort by time": "時間排序", "Sort by time": "時間排序",
"Time": "時間", "Time": "時間",
"Export history": "匯出錄", "Export history": "匯出錄",
"Import history": "匯入錄", "Import history": "匯入錄",
"Clear history": "清空錄", "Clear history": "清空錄",
"Refresh history": "更新紀錄", "Refresh history": "重新整理記錄",
"No history": "沒有錄", "No history": "沒有錄",
"Import from browser": "從瀏覽器匯入", "Import from browser": "從瀏覽器匯入",
"Releases": "版本", "Releases": "版本",
"Are you sure?": "確定嗎?", "Are you sure?": "確定嗎?",
"Do you really want to delete this note?": "確定要刪除這個文件嗎", "Do you really want to delete this note?": "確定刪除這則筆記",
"All users will lose their connection.": "所有使用者將會失去連線", "All users will lose their connection.": "所有使用者將會失去連線",
"Cancel": "取消", "Cancel": "取消",
"Yes, do it!": "沒錯,就這樣辦", "Yes, do it!": "沒錯,就這麼做",
"Choose method": "選擇方式", "Choose method": "選擇方式",
"Sign in via %s": "透過 %s 登入", "Sign in via %s": "透過 %s 登入",
"New": "新增", "New": "新增",
"Publish": "發", "Publish": "發",
"Extra": "增益", "Extra": "增益",
"Revision": "修訂版本", "Revision": "修訂版本",
"Slide Mode": "簡報模式", "Slide Mode": "簡報模式",
@ -55,7 +55,7 @@
"You have an incompatible client version.": "您使用的是不相容的客戶端", "You have an incompatible client version.": "您使用的是不相容的客戶端",
"Refresh to update.": "請重新整理來更新", "Refresh to update.": "請重新整理來更新",
"New version available!": "新版本來了!", "New version available!": "新版本來了!",
"See releases notes here": "請由此查閱更新錄", "See releases notes here": "請由此查閱更新錄",
"Refresh to enjoy new features.": "請重新整理來享受最新功能", "Refresh to enjoy new features.": "請重新整理來享受最新功能",
"Your user state has changed.": "您的使用者狀態已變更", "Your user state has changed.": "您的使用者狀態已變更",
"Refresh to load new user state.": "請重新整理來載入新的使用者狀態", "Refresh to load new user state.": "請重新整理來載入新的使用者狀態",
@ -66,7 +66,7 @@
"Send us email": "寄信給我們", "Send us email": "寄信給我們",
"Documents": "文件", "Documents": "文件",
"Features": "功能簡介", "Features": "功能簡介",
"YAML Metadata": "YAML Metadata", "YAML Metadata": "YAML 中繼資料",
"Slide Example": "簡報範例", "Slide Example": "簡報範例",
"Cheatsheet": "快速簡表", "Cheatsheet": "快速簡表",
"Example": "範例", "Example": "範例",
@ -88,7 +88,7 @@
"This is a alert area.": "這是警告區塊", "This is a alert area.": "這是警告區塊",
"Revert": "還原", "Revert": "還原",
"Import from clipboard": "從剪貼簿匯入", "Import from clipboard": "從剪貼簿匯入",
"Paste your markdown or webpage here...": "在這裡貼上 Markdown 或是網頁內容...", "Paste your markdown or webpage here...": "在這裡貼上 Markdown 或是網頁內容",
"Clear": "清除", "Clear": "清除",
"This note is locked": "此份筆記已被鎖定", "This note is locked": "此份筆記已被鎖定",
"Sorry, only owner can edit this note.": "抱歉,只有擁有者可以編輯此筆記", "Sorry, only owner can edit this note.": "抱歉,只有擁有者可以編輯此筆記",
@ -97,23 +97,23 @@
"Sorry, you've reached the max length this note can be.": "抱歉,您已使用到此份筆記可用的最大長度", "Sorry, you've reached the max length this note can be.": "抱歉,您已使用到此份筆記可用的最大長度",
"Please reduce the content or divide it to more notes, thank you!": "請減少內容或是將內容切成更多筆記,謝謝!", "Please reduce the content or divide it to more notes, thank you!": "請減少內容或是將內容切成更多筆記,謝謝!",
"Import from Gist": "從 Gist 匯入", "Import from Gist": "從 Gist 匯入",
"Paste your gist url here...": "在這裡貼上 gist 網址...", "Paste your gist url here...": "在此處貼上 gist 網址…",
"Import from Snippet": "從 Snippet 匯入", "Import from Snippet": "從 Snippet 匯入",
"Select From Available Projects": "從可用專案選擇", "Select From Available Projects": "從可用專案選擇",
"Select From Available Snippets": "從可用的 Snippets 選擇", "Select From Available Snippets": "從可用的 Snippets 選擇",
"OR": "或是", "OR": "或是",
"Export to Snippet": "匯出 Snippet", "Export to Snippet": "匯出 Snippet",
"Select Visibility Level": "選擇可見層級", "Select Visibility Level": "選擇可見層級",
"Night Theme": "夜間主題", "Night Theme": "夜間主題",
"Follow us on %s and %s.": "來 %s 或 %s 和我們互動吧!", "Follow us on %s and %s.": "來 %s 或 %s 和我們互動吧!",
"Privacy": "隱私權政策", "Privacy": "隱私權政策",
"Terms of Use": "使用條款", "Terms of Use": "使用條款",
"Do you really want to delete your user account?": "你確定真的想要刪除帳戶?", "Do you really want to delete your user account?": "你確定真的想要刪除帳戶?",
"This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "我們將會刪除你的帳戶、你所擁有的筆記、以及你在別人筆記裡的作者錄。", "This will delete your account, all notes that are owned by you and remove all references to your account from other notes.": "我們將會刪除你的帳戶、你所擁有的筆記、以及你在別人筆記裡的作者錄。",
"Delete user": "刪除使用者", "Delete user": "刪除使用者",
"Export user data": "匯出使用者資料", "Export user data": "匯出使用者資料",
"Help us translating on %s": "來 %s 幫我們翻譯", "Help us translating on %s": "來 %s 幫我們翻譯",
"Source Code": "原始碼", "Source Code": "原始碼",
"Powered by %s": "Powered by %s", "Powered by %s": "技術支援:%s",
"Register": "註冊" "Register": "註冊"
} }

View File

@ -26,7 +26,7 @@
"test": "npm run-script eslint && npm run-script jsonlint && mocha" "test": "npm run-script eslint && npm run-script jsonlint && mocha"
}, },
"dependencies": { "dependencies": {
"@hackmd/codemirror": "~5.41.2", "@hackmd/codemirror": "^5.46.2",
"@hackmd/diff-match-patch": "~1.1.1", "@hackmd/diff-match-patch": "~1.1.1",
"@hackmd/idle-js": "~1.0.1", "@hackmd/idle-js": "~1.0.1",
"@hackmd/imgur": "~0.4.1", "@hackmd/imgur": "~0.4.1",
@ -55,7 +55,7 @@
"express": "~4.16.4", "express": "~4.16.4",
"express-session": "~1.16.1", "express-session": "~1.16.1",
"file-saver": "~1.3.3", "file-saver": "~1.3.3",
"flowchart.js": "~1.6.4", "flowchart.js": "~1.12.0",
"fork-awesome": "~1.1.3", "fork-awesome": "~1.1.3",
"formidable": "~1.2.1", "formidable": "~1.2.1",
"gist-embed": "~2.6.0", "gist-embed": "~2.6.0",