Gitlab Community Edition Instance
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
pad
gwdg_codimd_server
Commits
506dbf01
Commit
506dbf01
authored
May 20, 2019
by
hholder
Browse files
add images correctly
parent
e9acbd25
Changes
61
Expand all
Hide whitespace changes
Inline
Side-by-side
.travis.yml
View file @
506dbf01
...
...
@@ -8,12 +8,6 @@ env:
jobs
:
include
:
-
env
:
task=npm-test
node_js
:
-
6
before_install
:
-
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "$YARN_VERSION"
-
export PATH="$HOME/.yarn/bin:$PATH"
-
env
:
task=npm-test
node_js
:
-
8
...
...
README.md
View file @
506dbf01
This diff is collapsed.
Click to expand it.
bin/manage_users
View file @
506dbf01
#!/usr/bin/env node
// First configure the logger so it does not spam the console
const
logger
=
require
(
"../lib/logger"
);
logger
.
transports
.
forEach
((
transport
)
=>
transport
.
level
=
"warning"
)
const
logger
=
require
(
'../lib/logger'
)
logger
.
transports
.
forEach
((
transport
)
=>
{
transport
.
level
=
'warning'
})
const
models
=
require
(
"
../lib/models/
"
);
const
readline
=
require
(
"
readline-sync
"
);
const
minimist
=
require
(
"
minimist
"
);
const
models
=
require
(
'
../lib/models/
'
)
const
readline
=
require
(
'
readline-sync
'
)
const
minimist
=
require
(
'
minimist
'
)
function
showUsage
(
tips
)
{
console
.
log
(
`${tips}
function
showUsage
(
tips
)
{
console
.
log
(
`${tips}
Command-line utility to create users for email-signin.
Usage: bin/manage_users [--pass password] (--add | --del) user-email
Options:
--add
Add user with the specified user-email
--del
Delete user with specified user-email
--reset
Reset user password with specified user-email
--pass
Use password from cmdline rather than prompting
`
)
;
process
.
exit
(
1
)
;
Options:
--add
\t
Add user with the specified user-email
--del
\t
Delete user with specified user-email
--reset
\t
Reset user password with specified user-email
--pass
\t
Use password from cmdline rather than prompting
`
)
process
.
exit
(
1
)
}
function
getPass
(
argv
,
action
)
{
// Find whether we use cmdline or prompt password
if
(
typeof
argv
[
"
pass
"
]
!==
'string'
)
{
return
readline
.
question
(
`Password for ${argv[action]}:`
,
{
hideEchoBack
:
true
})
;
}
console
.
log
(
"
Using password from commandline...
"
);
return
argv
[
"
pass
"
];
function
getPass
(
argv
,
action
)
{
// Find whether we use cmdline or prompt password
if
(
typeof
argv
[
'
pass
'
]
!==
'string'
)
{
return
readline
.
question
(
`Password for ${argv[action]}:`
,
{
hideEchoBack
:
true
})
}
console
.
log
(
'
Using password from commandline...
'
)
return
argv
[
'
pass
'
]
}
// Using an async function to be able to use await inside
async
function
createUser
(
argv
)
{
const
existing_user
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
"add"
]}});
// Cannot create already-existing users
if
(
existing_user
!=
undefined
)
{
console
.
log
(
`User with e-mail ${existing_user.email} already exists! Aborting ...`
);
process
.
exit
(
1
);
}
const
pass
=
getPass
(
argv
,
"add"
);
// Lets try to create, and check success
const
ref
=
await
models
.
User
.
create
({
email
:
argv
[
"add"
],
password
:
pass
});
if
(
ref
==
undefined
)
{
console
.
log
(
`Could not create user with email ${argv["add"]}`
);
process
.
exit
(
1
);
}
else
console
.
log
(
`Created user with email ${argv["add"]}`
);
async
function
createUser
(
argv
)
{
const
existingUser
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
'add'
]
}
})
// Cannot create already-existing users
if
(
existingUser
!==
undefined
)
{
console
.
log
(
`User with e-mail ${existingUser.email} already exists! Aborting ...`
)
process
.
exit
(
1
)
}
const
pass
=
getPass
(
argv
,
'add'
)
// Lets try to create, and check success
const
ref
=
await
models
.
User
.
create
({
email
:
argv
[
'add'
],
password
:
pass
})
if
(
ref
===
undefined
)
{
console
.
log
(
`Could not create user with email ${argv['add']}`
)
process
.
exit
(
1
)
}
else
{
console
.
log
(
`Created user with email ${argv['add']}`
)
}
}
// Using an async function to be able to use await inside
async
function
deleteUser
(
argv
)
{
// Cannot delete non-existing users
const
existing
_u
ser
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
"
del
"
]}
})
;
if
(
existing
_u
ser
===
undefined
)
{
console
.
log
(
`User with e-mail ${argv[
"
del
"
]} does not exist, cannot delete`
)
;
process
.
exit
(
1
)
;
}
// Sadly .destroy() does not return any success value with all
// backends. See sequelize #4124
await
existing
_u
ser
.
destroy
()
;
console
.
log
(
`Deleted user ${argv[
"
del
"
]} ...`
)
;
async
function
deleteUser
(
argv
)
{
// Cannot delete non-existing users
const
existing
U
ser
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
'
del
'
]
}
})
if
(
existing
U
ser
===
undefined
)
{
console
.
log
(
`User with e-mail ${argv[
'
del
'
]} does not exist, cannot delete`
)
process
.
exit
(
1
)
}
// Sadly .destroy() does not return any success value with all
// backends. See sequelize #4124
await
existing
U
ser
.
destroy
()
console
.
log
(
`Deleted user ${argv[
'
del
'
]} ...`
)
}
// Using an async function to be able to use await inside
async
function
resetUser
(
argv
)
{
const
existing
_u
ser
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
"
reset
"
]}
})
;
// Cannot reset non-existing users
if
(
existing
_u
ser
==
undefined
)
{
console
.
log
(
`User with e-mail ${argv[
"
reset
"
]} does not exist, cannot reset`
)
;
process
.
exit
(
1
)
;
}
const
pass
=
getPass
(
argv
,
"
reset
"
);
// set password and save
existing
_u
ser
.
password
=
pass
;
await
existing
_u
ser
.
save
()
;
console
.
log
(
`User with email ${argv[
"
reset
"
]} password has been reset`
)
;
async
function
resetUser
(
argv
)
{
const
existing
U
ser
=
await
models
.
User
.
findOne
({
where
:
{
email
:
argv
[
'
reset
'
]
}
})
// Cannot reset non-existing users
if
(
existing
U
ser
==
=
undefined
)
{
console
.
log
(
`User with e-mail ${argv[
'
reset
'
]} does not exist, cannot reset`
)
process
.
exit
(
1
)
}
const
pass
=
getPass
(
argv
,
'
reset
'
)
// set password and save
existing
U
ser
.
password
=
pass
await
existing
U
ser
.
save
()
console
.
log
(
`User with email ${argv[
'
reset
'
]} password has been reset`
)
}
const
options
=
{
add
:
createUser
,
del
:
deleteUser
,
reset
:
resetUser
,
}
;
add
:
createUser
,
del
:
deleteUser
,
reset
:
resetUser
}
// Perform commandline-parsing
const
argv
=
minimist
(
process
.
argv
.
slice
(
2
))
;
const
argv
=
minimist
(
process
.
argv
.
slice
(
2
))
const
keys
=
Object
.
keys
(
options
)
;
const
opts
=
keys
.
filter
((
key
)
=>
argv
[
key
]
!==
undefined
)
;
const
action
=
opts
[
0
]
;
const
keys
=
Object
.
keys
(
options
)
const
opts
=
keys
.
filter
((
key
)
=>
argv
[
key
]
!==
undefined
)
const
action
=
opts
[
0
]
// Check for options missing
if
(
opts
.
length
===
0
)
{
showUsage
(
`You did not specify either ${keys.map((key) => `
--
$
{
key
}
`).join(' or ')}!`
)
;
showUsage
(
`You did not specify either ${keys.map((key) => `
--
$
{
key
}
`).join(' or ')}!`
)
}
// Check if both are specified
if
(
opts
.
length
>
1
)
{
showUsage
(
`You cannot ${action.join(' and ')} at the same time!`
)
;
showUsage
(
`You cannot ${action.join(' and ')} at the same time!`
)
}
// Check if not string
if
(
typeof
argv
[
action
]
!==
'string'
)
{
showUsage
(
`You must follow an email after --${action}`
)
;
showUsage
(
`You must follow an email after --${action}`
)
}
// Call respective processing functions
options
[
action
](
argv
)
.
then
(
function
()
{
process
.
exit
(
0
)
;
})
;
options
[
action
](
argv
)
.
then
(
function
()
{
process
.
exit
(
0
)
})
lib/config/default.js
View file @
506dbf01
...
...
@@ -66,7 +66,8 @@ module.exports = {
s3
:
{
accessKeyId
:
undefined
,
secretAccessKey
:
undefined
,
region
:
undefined
region
:
undefined
,
endpoint
:
undefined
},
minio
:
{
accessKey
:
undefined
,
...
...
lib/config/environment.js
View file @
506dbf01
'
use strict
'
const
{
toBooleanConfig
,
toArrayConfig
,
toIntegerConfig
}
=
require
(
'
./utils
'
)
const
{
toBooleanConfig
,
toArrayConfig
,
toIntegerConfig
}
=
require
(
'
./utils
'
)
module
.
exports
=
{
sourceURL
:
process
.
env
.
CMD_SOURCE_URL
,
...
...
@@ -40,7 +40,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
,
...
...
lib/config/hackmdEnvironment.js
View file @
506dbf01
'
use strict
'
const
{
toBooleanConfig
,
toArrayConfig
,
toIntegerConfig
}
=
require
(
'
./utils
'
)
const
{
toBooleanConfig
,
toArrayConfig
,
toIntegerConfig
}
=
require
(
'
./utils
'
)
module
.
exports
=
{
domain
:
process
.
env
.
HMD_DOMAIN
,
...
...
lib/config/index.js
View file @
506dbf01
...
...
@@ -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
...
...
lib/config/oldEnvironment.js
View file @
506dbf01
'
use strict
'
const
{
toBooleanConfig
}
=
require
(
'
./utils
'
)
const
{
toBooleanConfig
}
=
require
(
'
./utils
'
)
module
.
exports
=
{
debug
:
toBooleanConfig
(
process
.
env
.
DEBUG
),
...
...
lib/history.js
View file @
506dbf01
'
use strict
'
// history
// external modules
var
LZString
=
require
(
'
lz-string
'
)
var
LZString
=
require
(
'
@hackmd/
lz-string
'
)
// core
var
config
=
require
(
'
./config
'
)
...
...
lib/letter-avatars.js
View file @
506dbf01
...
...
@@ -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://www.gravatar.com/avatar/
'
+
hexDigest
;
photo
=
'
https://www.gravatar.com/avatar/
'
+
hexDigest
if
(
big
)
{
photo
+=
'
?s=400
'
}
else
{
...
...
lib/logger.js
View file @
506dbf01
'
use strict
'
const
{
createLogger
,
format
,
transports
}
=
require
(
'
winston
'
)
const
{
createLogger
,
format
,
transports
}
=
require
(
'
winston
'
)
const
logger
=
createLogger
({
level
:
'
debug
'
,
...
...
lib/migrations/20160112220142-note-add-lastchange.js
View file @
506dbf01
...
...
@@ -18,8 +18,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
'
)
})
}
}
lib/migrations/20171009121200-longtext-for-mysql.js
View file @
506dbf01
'
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
})
}
}
lib/migrations/20180209120907-longtext-of-authorship.js
View file @
506dbf01
'
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
})
}
}
lib/migrations/20180306150303-fix-enum.js
View file @
506dbf01
'
use strict
'
module
.
exports
=
{
up
:
function
(
queryInterface
,
Sequelize
)
{
queryInterface
.
changeColumn
(
'
Notes
'
,
'
permission
'
,
{
type
:
Sequelize
.
ENUM
(
'
freely
'
,
'
editable
'
,
'
limited
'
,
'
locked
'
,
'
protected
'
,
'
private
'
)})
up
:
async
function
(
queryInterface
,
Sequelize
)
{
await
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
'
)})
down
:
async
function
(
queryInterface
,
Sequelize
)
{
await
queryInterface
.
changeColumn
(
'
Notes
'
,
'
permission
'
,
{
type
:
Sequelize
.
ENUM
(
'
freely
'
,
'
editable
'
,
'
locked
'
,
'
private
'
)
})
}
}
lib/models/author.js
View file @
506dbf01
...
...
@@ -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
})
}
}
]
})
Author
.
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
})
}
return
Author
}
lib/models/index.js
View file @
506dbf01
...
...
@@ -3,14 +3,16 @@
var
fs
=
require
(
'
fs
'
)
var
path
=
require
(
'
path
'
)
var
Sequelize
=
require
(
'
sequelize
'
)
const
{
cloneDeep
}
=
require
(
'
lodash
'
)
const
{
cloneDeep
}
=
require
(
'
lodash
'
)
// core
var
config
=
require
(
'
../config
'
)
var
logger
=
require
(
'
../logger
'
)
var
dbconfig
=
cloneDeep
(
config
.
db
)
dbconfig
.
logging
=
config
.
debug
?
logger
.
info
:
false
dbconfig
.
logging
=
config
.
debug
?
(
data
)
=>
{
logger
.
info
(
data
)
}
:
false
var
sequelize
=
null
...
...
@@ -39,13 +41,13 @@ sequelize.processData = processData
var
db
=
{}
fs
.
readdirSync
(
__dirname
)
.
filter
(
function
(
file
)
{
return
(
file
.
indexOf
(
'
.
'
)
!==
0
)
&&
(
file
!==
'
index.js
'
)
})
.
forEach
(
function
(
file
)
{
var
model
=
sequelize
.
import
(
path
.
join
(
__dirname
,
file
))
db
[
model
.
name
]
=
model
})
.
filter
(
function
(
file
)
{
return
(
file
.
indexOf
(
'
.
'
)
!==
0
)
&&
(
file
!==
'
index.js
'
)
})
.
forEach
(
function
(
file
)
{
var
model
=
sequelize
.
import
(
path
.
join
(
__dirname
,
file
))
db
[
model
.
name
]
=
model
})
Object
.
keys
(
db
).
forEach
(
function
(
modelName
)
{
if
(
'
associate
'
in
db
[
modelName
])
{
...
...
lib/models/note.js
View file @
506dbf01
This diff is collapsed.
Click to expand it.
lib/models/revision.js
View file @
506dbf01
...
...
@@ -7,6 +7,8 @@ var childProcess = require('child_process')
var
shortId
=
require
(
'
shortid
'
)
var
path
=
require
(
'
path
'
)
var
Op
=
Sequelize
.
Op
// core
var
config
=
require
(
'
../config
'
)
var
logger
=
require
(
'
../logger
'
)
...
...
@@ -97,214 +99,212 @@ module.exports = function (sequelize, DataTypes) {
this
.
setDataValue
(
'
authorship
'
,
value
?
JSON
.
stringify
(
value
)
:
value
)
}
}
},
{
classMethods
:
{
associate
:
function
(
models
)
{
Revision
.
belongsTo
(
models
.
Note
,
{
foreignKey
:
'
noteId
'
,
as
:
'
note
'
,
constraints
:
false
,
onDelete
:
'
CASCADE
'
,
hooks
:
true
})
},
getNoteRevisions
:
function
(
note
,
callback
)
{
Revision
.
findAll
({
where
:
{
noteId
:
note
.
id
},
order
:
[[
'
createdAt
'
,
'
DESC
'
]]
}).
then
(
function
(
revisions
)
{
var
data
=
[]
for
(
var
i
=
0
,
l
=
revisions
.
length
;
i
<
l
;
i
++
)
{
var
revision
=
revisions
[
i
]
data
.
push
({
time
:
moment
(
revision
.
createdAt
).
valueOf
(),
length
:
revision
.
length
})
}
callback
(
null
,
data
)
}).
catch
(
function
(
err
)
{
callback
(
err
,
null
)
})
})
Revision
.
associate
=
function
(
models
)
{
Revision
.
belongsTo
(
models
.
Note
,
{
foreignKey
:
'
noteId
'
,
as
:
'
note
'
,
constraints
:
false
,
onDelete
:
'
CASCADE
'
,
hooks
:
true
})
}
Revision
.
getNoteRevisions
=
function
(
note
,
callback
)
{
Revision
.
findAll
({
where
:
{
noteId
:
note
.
id
},
getPatchedNoteRevisionByTime
:
function
(
note
,
time
,
callback
)
{
// find all revisions to prepare for all possible calculation
Revision
.
findAll
({
where
:
{
noteId
:
note
.
id
},
order
:
[[
'
createdAt
'
,
'
DESC
'
]]
}).
then
(
function
(
revisions
)
{
if
(
revisions
.
length
<=
0
)
return
callback
(
null
,
null
)
// measure target revision position
Revision
.
count
({
where
:
{
noteId
:
note
.
id
,
createdAt
:
{
$gte
:
time
}
},
order
:
[[
'
createdAt
'
,
'
DESC
'
]]
}).
then
(
function
(
count
)
{
if
(
count
<=
0
)
return
callback
(
null
,
null
)
sendDmpWorker
({
msg
:
'
get revision
'
,
revisions
:
revisions
,
count
:
count
},
callback
)
}).
catch
(
function
(
err
)
{
return
callback
(
err
,
null
)
})
}).
catch
(
function
(
err
)
{
return
callback
(
err
,
null
)
order
:
[[
'
createdAt
'
,
'
DESC
'
]]
}).
then
(
function
(
revisions
)
{
var
data
=
[]
for
(
var
i
=
0
,
l
=
revisions
.
length
;
i
<
l
;
i
++
)
{