mirror of
https://github.com/wekan/wekan.git
synced 2025-12-18 00:10:13 +01:00
Merge branch 'master' of https://github.com/wekan/wekan
This commit is contained in:
commit
efdab37f3f
87 changed files with 35503 additions and 44501 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -29,3 +29,6 @@ versions.json
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
package-lock.json
|
||||||
|
.meteor/local
|
||||||
|
.meteor-1.6-snap/.meteor/local
|
||||||
|
|
|
||||||
|
|
@ -91,3 +91,8 @@ mdg:meteor-apm-agent
|
||||||
meteorhacks:unblock
|
meteorhacks:unblock
|
||||||
lucasantoniassi:accounts-lockout
|
lucasantoniassi:accounts-lockout
|
||||||
wekan-markdown
|
wekan-markdown
|
||||||
|
konecty:mongo-counter
|
||||||
|
percolate:synced-cron
|
||||||
|
easylogic:summernote
|
||||||
|
cfs:filesystem
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ cfs:collection@0.5.5
|
||||||
cfs:collection-filters@0.2.4
|
cfs:collection-filters@0.2.4
|
||||||
cfs:data-man@0.0.6
|
cfs:data-man@0.0.6
|
||||||
cfs:file@0.1.17
|
cfs:file@0.1.17
|
||||||
|
cfs:filesystem@0.1.2
|
||||||
cfs:gridfs@0.0.34
|
cfs:gridfs@0.0.34
|
||||||
cfs:http-methods@0.0.32
|
cfs:http-methods@0.0.32
|
||||||
cfs:http-publish@0.0.13
|
cfs:http-publish@0.0.13
|
||||||
|
|
@ -55,6 +56,7 @@ ddp-server@2.1.1
|
||||||
deps@1.0.12
|
deps@1.0.12
|
||||||
diff-sequence@1.0.7
|
diff-sequence@1.0.7
|
||||||
dynamic-import@0.2.1
|
dynamic-import@0.2.1
|
||||||
|
easylogic:summernote@0.8.8
|
||||||
ecmascript@0.9.0
|
ecmascript@0.9.0
|
||||||
ecmascript-runtime@0.5.0
|
ecmascript-runtime@0.5.0
|
||||||
ecmascript-runtime-client@0.5.0
|
ecmascript-runtime-client@0.5.0
|
||||||
|
|
@ -77,6 +79,7 @@ kadira:blaze-layout@2.3.0
|
||||||
kadira:dochead@1.5.0
|
kadira:dochead@1.5.0
|
||||||
kadira:flow-router@2.12.1
|
kadira:flow-router@2.12.1
|
||||||
kenton:accounts-sandstorm@0.7.0
|
kenton:accounts-sandstorm@0.7.0
|
||||||
|
konecty:mongo-counter@0.0.5_3
|
||||||
lamhieu:meteorx@2.0.1
|
lamhieu:meteorx@2.0.1
|
||||||
launch-screen@1.1.1
|
launch-screen@1.1.1
|
||||||
livedata@1.0.18
|
livedata@1.0.18
|
||||||
|
|
@ -170,6 +173,7 @@ templating-compiler@1.3.3
|
||||||
templating-runtime@1.3.2
|
templating-runtime@1.3.2
|
||||||
templating-tools@1.1.2
|
templating-tools@1.1.2
|
||||||
tracker@1.1.3
|
tracker@1.1.3
|
||||||
|
twbs:bootstrap@3.3.6
|
||||||
ui@1.0.13
|
ui@1.0.13
|
||||||
underscore@1.0.10
|
underscore@1.0.10
|
||||||
url@1.1.0
|
url@1.1.0
|
||||||
|
|
|
||||||
4572
.meteor-1.6-snap/package-lock.json
generated
4572
.meteor-1.6-snap/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "wekan",
|
"name": "wekan",
|
||||||
"version": "v3.08.0",
|
"version": "v3.15.0",
|
||||||
"description": "Open-Source kanban",
|
"description": "Open-Source kanban",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -53,16 +53,21 @@
|
||||||
"prettier-eslint": "^8.8.2"
|
"prettier-eslint": "^8.8.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.1.2",
|
"@babel/runtime": "^7.5.4",
|
||||||
|
"ajv": "^5.0.0",
|
||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"bson-ext": "^2.0.0",
|
"bcrypt": "^3.0.2",
|
||||||
|
"bson": "^4.0.0",
|
||||||
|
"bunyan": "^1.8.12",
|
||||||
"es6-promise": "^4.2.4",
|
"es6-promise": "^4.2.4",
|
||||||
"hoek": "^5.0.4",
|
"gridfs-stream": "^0.5.3",
|
||||||
|
"ldapjs": "^1.0.2",
|
||||||
"meteor-node-stubs": "^0.4.1",
|
"meteor-node-stubs": "^0.4.1",
|
||||||
|
"mongodb": "^2.2.19",
|
||||||
"os": "^0.1.1",
|
"os": "^0.1.1",
|
||||||
"page": "^1.8.6",
|
"page": "^1.8.6",
|
||||||
"qs": "^6.5.2",
|
"qs": "^6.5.2",
|
||||||
"source-map-support": "^0.5.9",
|
"source-map-support": "^0.5.12",
|
||||||
"xss": "^1.0.6"
|
"xss": "^1.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,3 +95,4 @@ wekan-markdown
|
||||||
konecty:mongo-counter
|
konecty:mongo-counter
|
||||||
percolate:synced-cron
|
percolate:synced-cron
|
||||||
easylogic:summernote
|
easylogic:summernote
|
||||||
|
cfs:filesystem
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ cfs:collection@0.5.5
|
||||||
cfs:collection-filters@0.2.4
|
cfs:collection-filters@0.2.4
|
||||||
cfs:data-man@0.0.6
|
cfs:data-man@0.0.6
|
||||||
cfs:file@0.1.17
|
cfs:file@0.1.17
|
||||||
|
cfs:filesystem@0.1.2
|
||||||
cfs:gridfs@0.0.34
|
cfs:gridfs@0.0.34
|
||||||
cfs:http-methods@0.0.32
|
cfs:http-methods@0.0.32
|
||||||
cfs:http-publish@0.0.13
|
cfs:http-publish@0.0.13
|
||||||
|
|
|
||||||
104
CHANGELOG.md
104
CHANGELOG.md
|
|
@ -1,3 +1,107 @@
|
||||||
|
# v3.15 2019-08-11 Wekan release
|
||||||
|
|
||||||
|
This release fixes the following bugs:
|
||||||
|
|
||||||
|
- [Try to fix Snap](https://github.com/wekan/wekan/commit/a1d883b22f73f4bef6d547f94dcb900f475fcb41).
|
||||||
|
Thanks to xet7.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
|
# v3.14 2019-08-11 Wekan release
|
||||||
|
|
||||||
|
This release adds the following new features:
|
||||||
|
|
||||||
|
- [On wekan master specifying ATTACHMENTS_STORE_PATH, it will try its best keeping original attachments, only newer
|
||||||
|
attachments will be stored into specified path](https://github.com/wekan/wekan/pull/2607).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
- [Made image upload in summernote as attachment to wekan board instead of base64 string,
|
||||||
|
which would make the comments use less bytes and be able to take advantage of using local file system feature
|
||||||
|
as attachment](https://github.com/wekan/wekan/pull/2608).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
|
||||||
|
and fixes the following bugs:
|
||||||
|
|
||||||
|
- [Fix bug: Unable to disable richer comment editor](https://github.com/wekan/wekan/pull/2607).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
- [Changed rm to rm -f in wekan snap build, and add packages that somehow didn't get install during snapcraft
|
||||||
|
build](https://github.com/wekan/wekan/pull/2608).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
|
# v3.13 2019-08-09 Wekan release
|
||||||
|
|
||||||
|
Update translations. Thanks to translators.
|
||||||
|
|
||||||
|
# v3.12 2019-08-09 Wekan release
|
||||||
|
|
||||||
|
This release adds the following new features:
|
||||||
|
|
||||||
|
- [Allowing wekan server admin to specify the attachments to be uploaded to server
|
||||||
|
file system instead of mongodb by specifying a system
|
||||||
|
env var: ATTACHMENTS_STORE_PATH](https://github.com/wekan/wekan/pull/2603).
|
||||||
|
The only caveat for this is if it's not a brand new wekan, if the wekan
|
||||||
|
server admin switchs to this setting, their old attachments won't be available
|
||||||
|
anymore, unless someone make a script to export them out to the filesystem.
|
||||||
|
Thanks to whowillcare.
|
||||||
|
- [Allowing user to insert video, link and image, or paste in html with sanitization.
|
||||||
|
In user comments display area, images can be clicked and shown as
|
||||||
|
swipebox](https://github.com/wekan/wekan/pull/2593).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
|
||||||
|
and fixes the following bugs:
|
||||||
|
|
||||||
|
- [Fix comment-editor marking issue](https://github.com/wekan/wekan/issues/2575).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
- [Bugfix: style kbd font color became white after introduced summernote editor
|
||||||
|
to card comments](https://github.com/wekan/wekan/pull/2600).
|
||||||
|
Thanks to whowillcare.
|
||||||
|
- [Show All Boards / Clone Board and Archive Board only to BoardAdmin/Admin/Sandstorm users
|
||||||
|
on desktop webbrowser view, so that it's not possible for normal users to make accidental
|
||||||
|
clicks to those](https://github.com/wekan/wekan/issues/2599).
|
||||||
|
Thanks to derbolle and xet7.
|
||||||
|
- [Fix bug on editing users informations, switching to other view, staring
|
||||||
|
a board](https://github.com/wekan/wekan/issues/2590).
|
||||||
|
Thanks to road42.
|
||||||
|
- [Fix null access with board body](https://github.com/wekan/wekan/pull/2602).
|
||||||
|
Thanks to justinr1234.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
|
# v3.11 2019-08-07 Wekan release
|
||||||
|
|
||||||
|
This release fixes the following bugs:
|
||||||
|
|
||||||
|
- [Remove non-existing file from snapcraft.yaml to get Snap to build](https://github.com/wekan/wekan/commit/ad82a900e8ec636a72c6e74bb8489559ce2a8bf0).
|
||||||
|
Thanks to xet7.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
|
# v3.10 2019-08-07 Wekan release
|
||||||
|
|
||||||
|
This release fixes the following bugs:
|
||||||
|
|
||||||
|
- [Add missing dependencies back and revert deleting phantomjs](https://github.com/wekan/wekan/commit/32e9aa0ddaf1b015825b8c62ad17ed74b449e4b1).
|
||||||
|
Thanks to whowillcare and xet7.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
|
# v3.09 2019-08-07 Wekan release
|
||||||
|
|
||||||
|
This release adds the following features:
|
||||||
|
|
||||||
|
- [Hide minicard label text: per user checkbox setting at sidebar](https://github.com/wekan/wekan/commit/f7e0b837d394d55d66d451c34f43fa8afd357e5b).
|
||||||
|
Thanks to xet7.
|
||||||
|
|
||||||
|
and fixes the following bugs:
|
||||||
|
|
||||||
|
- [Make Save button visible again at Admin Panel People Edit](https://github.com/wekan/wekan/commit/716fc32968e7dd51b64a11c6c33e59aee849c982).
|
||||||
|
Thanks to sclerc-chss and xet7.
|
||||||
|
- [Fix checking if API is enabled](https://github.com/wekan/wekan/pull/2588).
|
||||||
|
Thanks to justinr1234.
|
||||||
|
|
||||||
|
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||||
|
|
||||||
# v3.08 2019-08-07 Wekan release
|
# v3.08 2019-08-07 Wekan release
|
||||||
|
|
||||||
This release fixes the following bugs:
|
This release fixes the following bugs:
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 g++ build-essential
|
||||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60 \
|
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60 \
|
||||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15 \
|
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15 \
|
||||||
RICHER_CARD_COMMENT_EDITOR=true \
|
RICHER_CARD_COMMENT_EDITOR=true \
|
||||||
|
ATTACHMENTS_STORE_PATH="" \
|
||||||
MAX_IMAGE_PIXEL="" \
|
MAX_IMAGE_PIXEL="" \
|
||||||
IMAGE_COMPRESS_RATIO="" \
|
IMAGE_COMPRESS_RATIO="" \
|
||||||
BIGEVENTS_PATTERN="" \
|
BIGEVENTS_PATTERN="" \
|
||||||
|
|
@ -259,8 +260,8 @@ RUN \
|
||||||
#gosu wekan:wekan npm install bcrypt && \
|
#gosu wekan:wekan npm install bcrypt && \
|
||||||
#
|
#
|
||||||
# Delete phantomjs
|
# Delete phantomjs
|
||||||
cd /home/wekan/app_build/bundle && \
|
#cd /home/wekan/app_build/bundle && \
|
||||||
find . -name "*phantomjs*" | xargs rm -rf && \
|
#find . -name "*phantomjs*" | xargs rm -rf && \
|
||||||
#
|
#
|
||||||
cd /home/wekan/app_build/bundle/programs/server/ && \
|
cd /home/wekan/app_build/bundle/programs/server/ && \
|
||||||
gosu wekan:wekan npm install && \
|
gosu wekan:wekan npm install && \
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||||
appVersion: "v3.08.0"
|
appVersion: "v3.15.0"
|
||||||
files:
|
files:
|
||||||
userUploads:
|
userUploads:
|
||||||
- README.md
|
- README.md
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ BlazeComponent.extendComponent({
|
||||||
resetCommentInput(input);
|
resetCommentInput(input);
|
||||||
Tracker.flush();
|
Tracker.flush();
|
||||||
autosize.update(input);
|
autosize.update(input);
|
||||||
|
input.trigger('submitted');
|
||||||
}
|
}
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
},
|
},
|
||||||
|
|
@ -54,7 +55,7 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
// XXX This should be a static method of the `commentForm` component
|
// XXX This should be a static method of the `commentForm` component
|
||||||
function resetCommentInput(input) {
|
function resetCommentInput(input) {
|
||||||
input.val('').trigger('input'); // without manually trigger, input event won't be fired
|
input.val(''); // without manually trigger, input event won't be fired
|
||||||
input.blur();
|
input.blur();
|
||||||
commentFormIsOpen.set(false);
|
commentFormIsOpen.set(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,28 @@ template(name="boardList")
|
||||||
i.fa.js-has-spenttime-cards(
|
i.fa.js-has-spenttime-cards(
|
||||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||||
i.fa.js-clone-board(
|
unless isMiniScreen
|
||||||
class="fa-clone"
|
if isSandstorm
|
||||||
title="{{_ 'duplicate-board'}}")
|
i.fa.js-clone-board(
|
||||||
i.fa.js-archive-board(
|
class="fa-clone"
|
||||||
class="fa-archive"
|
title="{{_ 'duplicate-board'}}")
|
||||||
title="{{_ 'archive-board'}}")
|
i.fa.js-archive-board(
|
||||||
|
class="fa-archive"
|
||||||
|
title="{{_ 'archive-board'}}")
|
||||||
|
else if currentUser.isBoardAdmin
|
||||||
|
i.fa.js-clone-board(
|
||||||
|
class="fa-clone"
|
||||||
|
title="{{_ 'duplicate-board'}}")
|
||||||
|
i.fa.js-archive-board(
|
||||||
|
class="fa-archive"
|
||||||
|
title="{{_ 'archive-board'}}")
|
||||||
|
else if currentUser.isAdmin
|
||||||
|
i.fa.js-clone-board(
|
||||||
|
class="fa-clone"
|
||||||
|
title="{{_ 'duplicate-board'}}")
|
||||||
|
i.fa.js-archive-board(
|
||||||
|
class="fa-archive"
|
||||||
|
title="{{_ 'archive-board'}}")
|
||||||
|
|
||||||
template(name="boardListHeaderBar")
|
template(name="boardListHeaderBar")
|
||||||
h1 {{_ 'my-boards'}}
|
h1 {{_ 'my-boards'}}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ Template.boardListHeaderBar.events({
|
||||||
|
|
||||||
Template.boardListHeaderBar.helpers({
|
Template.boardListHeaderBar.helpers({
|
||||||
templatesBoardId() {
|
templatesBoardId() {
|
||||||
return Meteor.user().getTemplatesBoardId();
|
return Meteor.user() && Meteor.user().getTemplatesBoardId();
|
||||||
},
|
},
|
||||||
templatesBoardSlug() {
|
templatesBoardSlug() {
|
||||||
return Meteor.user().getTemplatesBoardSlug();
|
return Meteor.user() && Meteor.user().getTemplatesBoardSlug();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,24 +55,12 @@ Template.cardAttachmentsPopup.events({
|
||||||
'change .js-attach-file'(event) {
|
'change .js-attach-file'(event) {
|
||||||
const card = this;
|
const card = this;
|
||||||
const processFile = f => {
|
const processFile = f => {
|
||||||
const file = new FS.File(f);
|
Utils.processUploadedAttachment(card, f, attachment => {
|
||||||
if (card.isLinkedCard()) {
|
if (attachment && attachment._id && attachment.isImage()) {
|
||||||
file.boardId = Cards.findOne(card.linkedId).boardId;
|
card.setCover(attachment._id);
|
||||||
file.cardId = card.linkedId;
|
}
|
||||||
} else {
|
Popup.close();
|
||||||
file.boardId = card.boardId;
|
});
|
||||||
file.swimlaneId = card.swimlaneId;
|
|
||||||
file.listId = card.listId;
|
|
||||||
file.cardId = card._id;
|
|
||||||
}
|
|
||||||
file.userId = Meteor.userId();
|
|
||||||
const attachment = Attachments.insert(file);
|
|
||||||
|
|
||||||
if (attachment && attachment._id && attachment.isImage()) {
|
|
||||||
card.setCover(attachment._id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Popup.close();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FS.Utility.eachFile(event, f => {
|
FS.Utility.eachFile(event, f => {
|
||||||
|
|
@ -86,7 +74,7 @@ Template.cardAttachmentsPopup.events({
|
||||||
reader.onload = function(e) {
|
reader.onload = function(e) {
|
||||||
const dataurl = e && e.target && e.target.result;
|
const dataurl = e && e.target && e.target.result;
|
||||||
if (dataurl !== undefined) {
|
if (dataurl !== undefined) {
|
||||||
shrinkImage({
|
Utils.shrinkImage({
|
||||||
dataurl,
|
dataurl,
|
||||||
maxSize: MAX_IMAGE_PIXEL,
|
maxSize: MAX_IMAGE_PIXEL,
|
||||||
ratio: COMPRESS_RATIO,
|
ratio: COMPRESS_RATIO,
|
||||||
|
|
@ -118,59 +106,9 @@ Template.cardAttachmentsPopup.events({
|
||||||
'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
|
'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const MAX_IMAGE_PIXEL = Meteor.settings.public.MAX_IMAGE_PIXEL;
|
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
||||||
const COMPRESS_RATIO = Meteor.settings.public.IMAGE_COMPRESS_RATIO;
|
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
||||||
let pastedResults = null;
|
let pastedResults = null;
|
||||||
const shrinkImage = function(options) {
|
|
||||||
// shrink image to certain size
|
|
||||||
const dataurl = options.dataurl,
|
|
||||||
callback = options.callback,
|
|
||||||
toBlob = options.toBlob;
|
|
||||||
let canvas = document.createElement('canvas'),
|
|
||||||
image = document.createElement('img');
|
|
||||||
const maxSize = options.maxSize || 1024;
|
|
||||||
const ratio = options.ratio || 1.0;
|
|
||||||
const next = function(result) {
|
|
||||||
image = null;
|
|
||||||
canvas = null;
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback(result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
image.onload = function() {
|
|
||||||
let width = this.width,
|
|
||||||
height = this.height;
|
|
||||||
let changed = false;
|
|
||||||
if (width > height) {
|
|
||||||
if (width > maxSize) {
|
|
||||||
height *= maxSize / width;
|
|
||||||
width = maxSize;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
} else if (height > maxSize) {
|
|
||||||
width *= maxSize / height;
|
|
||||||
height = maxSize;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
canvas.width = width;
|
|
||||||
canvas.height = height;
|
|
||||||
canvas.getContext('2d').drawImage(this, 0, 0, width, height);
|
|
||||||
if (changed === true) {
|
|
||||||
const type = 'image/jpeg';
|
|
||||||
if (toBlob) {
|
|
||||||
canvas.toBlob(next, type, ratio);
|
|
||||||
} else {
|
|
||||||
next(canvas.toDataURL(type, ratio));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next(changed);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
image.onerror = function() {
|
|
||||||
next(false);
|
|
||||||
};
|
|
||||||
image.src = dataurl;
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.previewClipboardImagePopup.onRendered(() => {
|
Template.previewClipboardImagePopup.onRendered(() => {
|
||||||
// we can paste image from clipboard
|
// we can paste image from clipboard
|
||||||
|
|
@ -182,7 +120,7 @@ Template.previewClipboardImagePopup.onRendered(() => {
|
||||||
};
|
};
|
||||||
if (MAX_IMAGE_PIXEL) {
|
if (MAX_IMAGE_PIXEL) {
|
||||||
// if has size limitation on image we shrink it before uploading
|
// if has size limitation on image we shrink it before uploading
|
||||||
shrinkImage({
|
Utils.shrinkImage({
|
||||||
dataurl: results.dataURL,
|
dataurl: results.dataURL,
|
||||||
maxSize: MAX_IMAGE_PIXEL,
|
maxSize: MAX_IMAGE_PIXEL,
|
||||||
ratio: COMPRESS_RATIO,
|
ratio: COMPRESS_RATIO,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,12 @@ template(name="minicard")
|
||||||
if labels
|
if labels
|
||||||
.minicard-labels
|
.minicard-labels
|
||||||
each labels
|
each labels
|
||||||
span.card-label(class="card-label-{{color}}" title=name)
|
unless hiddenMinicardLabelText
|
||||||
+viewer
|
span.card-label(class="card-label-{{color}}" title=name)
|
||||||
= name
|
+viewer
|
||||||
|
= name
|
||||||
|
if hiddenMinicardLabelText
|
||||||
|
.minicard-label(class="card-label-{{color}}" title="{{name}}")
|
||||||
.minicard-title
|
.minicard-title
|
||||||
.handle
|
.handle
|
||||||
.fa.fa-arrows
|
.fa.fa-arrows
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,17 @@ BlazeComponent.extendComponent({
|
||||||
Utils.goBoardId(this.data().linkedId);
|
Utils.goBoardId(this.data().linkedId);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'click .js-toggle-minicard-label-text'() {
|
||||||
|
Meteor.call('toggleMinicardLabelText');
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
}).register('minicard');
|
}).register('minicard');
|
||||||
|
|
||||||
|
Template.minicard.helpers({
|
||||||
|
hiddenMinicardLabelText() {
|
||||||
|
return Meteor.user().hasHiddenMinicardLabelText();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,77 @@
|
||||||
|
import _sanitizeXss from 'xss';
|
||||||
|
const sanitizeXss = (input, options) => {
|
||||||
|
const defaultAllowedIframeSrc = /^(https:){0,1}\/\/.*?(youtube|vimeo|dailymotion|youku)/i;
|
||||||
|
const allowedIframeSrcRegex = (function() {
|
||||||
|
let reg = defaultAllowedIframeSrc;
|
||||||
|
const SAFE_IFRAME_SRC_PATTERN =
|
||||||
|
Meteor.settings.public.SAFE_IFRAME_SRC_PATTERN;
|
||||||
|
try {
|
||||||
|
if (SAFE_IFRAME_SRC_PATTERN !== undefined) {
|
||||||
|
reg = new RegExp(SAFE_IFRAME_SRC_PATTERN, 'i');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
/*eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||||
|
|
||||||
|
console.error('Wrong pattern specified', SAFE_IFRAM_SRC_PATTERN, e);
|
||||||
|
}
|
||||||
|
return reg;
|
||||||
|
})();
|
||||||
|
const targetWindow = '_blank';
|
||||||
|
options = {
|
||||||
|
onTag(tag, html, options) {
|
||||||
|
if (tag === 'iframe') {
|
||||||
|
const clipCls = 'note-vide-clip';
|
||||||
|
if (!options.isClosing) {
|
||||||
|
const srcp = /src=(['"]{0,1})(\S*)(\1)/;
|
||||||
|
let safe = html.indexOf(`class="${clipCls}"`) > -1;
|
||||||
|
if (srcp.exec(html)) {
|
||||||
|
const src = RegExp.$2;
|
||||||
|
if (allowedIframeSrcRegex.exec(src)) {
|
||||||
|
safe = true;
|
||||||
|
}
|
||||||
|
if (safe)
|
||||||
|
return `<iframe src='${src}' class="${clipCls}" width=100% height=auto allowfullscreen></iframe>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
} else if (tag === 'a') {
|
||||||
|
if (!options.isClosing) {
|
||||||
|
if (/href=(['"]{0,1})(\S*)(\1)/.exec(html)) {
|
||||||
|
const href = RegExp.$2;
|
||||||
|
if (href.match(/^((http(s){0,1}:){0,1}\/\/|\/)/)) {
|
||||||
|
// a valid url
|
||||||
|
return `<a href=${href} target=${targetWindow}>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tag === 'img') {
|
||||||
|
if (!options.isClosing) {
|
||||||
|
if (new RegExp('src=([\'"]{0,1})(\\S*)(\\1)').exec(html)) {
|
||||||
|
const src = RegExp.$2;
|
||||||
|
return `<a href='${src}' class='swipebox'><img src='${src}' class="attachment-image-preview mCS_img_loaded"></a>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
onTagAttr(tag, name, value) {
|
||||||
|
if (tag === 'img' && name === 'src') {
|
||||||
|
if (value && value.substr(0, 5) === 'data:') {
|
||||||
|
// allow image with dataURI src
|
||||||
|
return `${name}='${value}'`;
|
||||||
|
}
|
||||||
|
} else if (tag === 'a' && name === 'target') {
|
||||||
|
return `${name}='${targetWindow}'`; // always change a href target to a new window
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
return _sanitizeXss(input, options);
|
||||||
|
};
|
||||||
Template.editor.onRendered(() => {
|
Template.editor.onRendered(() => {
|
||||||
const textareaSelector = 'textarea';
|
const textareaSelector = 'textarea';
|
||||||
const enableRicherEditor =
|
|
||||||
Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR || true;
|
|
||||||
const mentions = [
|
const mentions = [
|
||||||
// User mentions
|
// User mentions
|
||||||
{
|
{
|
||||||
|
|
@ -32,7 +102,7 @@ Template.editor.onRendered(() => {
|
||||||
autosize($textarea);
|
autosize($textarea);
|
||||||
$textarea.escapeableTextComplete(mentions);
|
$textarea.escapeableTextComplete(mentions);
|
||||||
};
|
};
|
||||||
if (enableRicherEditor) {
|
if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR !== false) {
|
||||||
const isSmall = Utils.isMiniScreen();
|
const isSmall = Utils.isMiniScreen();
|
||||||
const toolbar = isSmall
|
const toolbar = isSmall
|
||||||
? [
|
? [
|
||||||
|
|
@ -50,47 +120,11 @@ Template.editor.onRendered(() => {
|
||||||
['color', ['color']],
|
['color', ['color']],
|
||||||
['para', ['ul', 'ol', 'paragraph']],
|
['para', ['ul', 'ol', 'paragraph']],
|
||||||
['table', ['table']],
|
['table', ['table']],
|
||||||
//['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
||||||
//['insert', ['link', 'picture']], // modal popup has issue somehow :(
|
//['insert', ['link', 'picture']], // modal popup has issue somehow :(
|
||||||
['view', ['fullscreen', 'help']],
|
['view', ['fullscreen', 'help']],
|
||||||
];
|
];
|
||||||
const cleanPastedHTML = function(input) {
|
const cleanPastedHTML = sanitizeXss;
|
||||||
const badTags = [
|
|
||||||
'style',
|
|
||||||
'script',
|
|
||||||
'applet',
|
|
||||||
'embed',
|
|
||||||
'noframes',
|
|
||||||
'noscript',
|
|
||||||
'meta',
|
|
||||||
'link',
|
|
||||||
'button',
|
|
||||||
'form',
|
|
||||||
].join('|');
|
|
||||||
const badPatterns = new RegExp(
|
|
||||||
`(?:${[
|
|
||||||
`<(${badTags})s*[^>][\\s\\S]*?<\\/\\1>`,
|
|
||||||
`<(${badTags})[^>]*?\\/>`,
|
|
||||||
].join('|')})`,
|
|
||||||
'gi',
|
|
||||||
);
|
|
||||||
let output = input;
|
|
||||||
// remove bad Tags
|
|
||||||
output = output.replace(badPatterns, '');
|
|
||||||
// remove attributes ' style="..."'
|
|
||||||
const badAttributes = new RegExp(
|
|
||||||
`(?:${[
|
|
||||||
'on\\S+=([\'"]?).*?\\1',
|
|
||||||
'href=([\'"]?)javascript:.*?\\2',
|
|
||||||
'style=([\'"]?).*?\\3',
|
|
||||||
'target=\\S+',
|
|
||||||
].join('|')})`,
|
|
||||||
'gi',
|
|
||||||
);
|
|
||||||
output = output.replace(badAttributes, '');
|
|
||||||
output = output.replace(/(<a )/gi, '$1target=_ '); // always to new target
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
const editor = '.editor';
|
const editor = '.editor';
|
||||||
const selectors = [
|
const selectors = [
|
||||||
`.js-new-comment-form ${editor}`,
|
`.js-new-comment-form ${editor}`,
|
||||||
|
|
@ -116,8 +150,8 @@ Template.editor.onRendered(() => {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
onInit(object) {
|
onInit(object) {
|
||||||
const originalInput = this;
|
const originalInput = this;
|
||||||
$(originalInput).on('input', function() {
|
$(originalInput).on('submitted', function() {
|
||||||
// when comment is submitted, the original textarea will be set to '', so shall we
|
// resetCommentInput has been called
|
||||||
if (!this.value) {
|
if (!this.value) {
|
||||||
const sn = getSummernote(this);
|
const sn = getSummernote(this);
|
||||||
sn && sn.summernote('reset');
|
sn && sn.summernote('reset');
|
||||||
|
|
@ -138,6 +172,77 @@ Template.editor.onRendered(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onImageUpload(files) {
|
||||||
|
const $summernote = getSummernote(this);
|
||||||
|
if (files && files.length > 0) {
|
||||||
|
const image = files[0];
|
||||||
|
const currentCard = Cards.findOne(Session.get('currentCard'));
|
||||||
|
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
||||||
|
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
||||||
|
const insertImage = src => {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = src;
|
||||||
|
img.setAttribute('width', '100%');
|
||||||
|
$summernote.summernote('insertNode', img);
|
||||||
|
};
|
||||||
|
const processData = function(fileObj) {
|
||||||
|
Utils.processUploadedAttachment(
|
||||||
|
currentCard,
|
||||||
|
fileObj,
|
||||||
|
attachment => {
|
||||||
|
if (
|
||||||
|
attachment &&
|
||||||
|
attachment._id &&
|
||||||
|
attachment.isImage()
|
||||||
|
) {
|
||||||
|
attachment.one('uploaded', function() {
|
||||||
|
const maxTry = 3;
|
||||||
|
const checkItvl = 500;
|
||||||
|
let retry = 0;
|
||||||
|
const checkUrl = function() {
|
||||||
|
// even though uploaded event fired, attachment.url() is still null somehow //TODO
|
||||||
|
const url = attachment.url();
|
||||||
|
if (url) {
|
||||||
|
insertImage(url);
|
||||||
|
} else {
|
||||||
|
retry++;
|
||||||
|
if (retry < maxTry) {
|
||||||
|
setTimeout(checkUrl, checkItvl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkUrl();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (MAX_IMAGE_PIXEL) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
const dataurl = e && e.target && e.target.result;
|
||||||
|
if (dataurl !== undefined) {
|
||||||
|
// need to shrink image
|
||||||
|
Utils.shrinkImage({
|
||||||
|
dataurl,
|
||||||
|
maxSize: MAX_IMAGE_PIXEL,
|
||||||
|
ratio: COMPRESS_RATIO,
|
||||||
|
toBlob: true,
|
||||||
|
callback(blob) {
|
||||||
|
if (blob !== false) {
|
||||||
|
blob.name = image.name;
|
||||||
|
processData(blob);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(image);
|
||||||
|
} else {
|
||||||
|
processData(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
onPaste() {
|
onPaste() {
|
||||||
// clear up unwanted tag info when user pasted in text
|
// clear up unwanted tag info when user pasted in text
|
||||||
const thisNote = this;
|
const thisNote = this;
|
||||||
|
|
@ -185,8 +290,6 @@ Template.editor.onRendered(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
import sanitizeXss from 'xss';
|
|
||||||
|
|
||||||
// XXX I believe we should compute a HTML rendered field on the server that
|
// XXX I believe we should compute a HTML rendered field on the server that
|
||||||
// would handle markdown and user mentions. We can simply have two
|
// would handle markdown and user mentions. We can simply have two
|
||||||
// fields, one source, and one compiled version (in HTML) and send only the
|
// fields, one source, and one compiled version (in HTML) and send only the
|
||||||
|
|
@ -237,32 +340,35 @@ Blaze.Template.registerHelper(
|
||||||
|
|
||||||
content = content.replace(fullMention, Blaze.toHTML(link));
|
content = content.replace(fullMention, Blaze.toHTML(link));
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTML.Raw(sanitizeXss(content));
|
return HTML.Raw(sanitizeXss(content));
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
Template.viewer.events({
|
Template.viewer.events({
|
||||||
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
||||||
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
||||||
// we stop these event at the viewer component level.
|
// we stop these event at the viewer component level.
|
||||||
'click a'(event, templateInstance) {
|
'click a'(event, templateInstance) {
|
||||||
event.stopPropagation();
|
let prevent = true;
|
||||||
|
|
||||||
// XXX We hijack the build-in browser action because we currently don't have
|
|
||||||
// `_blank` attributes in viewer links, and the transformer function is
|
|
||||||
// handled by a third party package that we can't configure easily. Fix that
|
|
||||||
// by using directly `_blank` attribute in the rendered HTML.
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const userId = event.currentTarget.dataset.userid;
|
const userId = event.currentTarget.dataset.userid;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
Popup.open('member').call({ userId }, event, templateInstance);
|
Popup.open('member').call({ userId }, event, templateInstance);
|
||||||
} else {
|
} else {
|
||||||
const href = event.currentTarget.href;
|
const href = event.currentTarget.href;
|
||||||
if (href) {
|
const child = event.currentTarget.firstElementChild;
|
||||||
|
if (child && child.tagName === 'IMG') {
|
||||||
|
prevent = false;
|
||||||
|
} else if (href) {
|
||||||
window.open(href, '_blank');
|
window.open(href, '_blank');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (prevent) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
// XXX We hijack the build-in browser action because we currently don't have
|
||||||
|
// `_blank` attributes in viewer links, and the transformer function is
|
||||||
|
// handled by a third party package that we can't configure easily. Fix that
|
||||||
|
// by using directly `_blank` attribute in the rendered HTML.
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ kbd
|
||||||
background: darken(white, 2%)
|
background: darken(white, 2%)
|
||||||
border-radius: 3px
|
border-radius: 3px
|
||||||
border: 1px solid darken(white, 10%)
|
border: 1px solid darken(white, 10%)
|
||||||
|
color: unset
|
||||||
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15)
|
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15)
|
||||||
|
|
||||||
.clear
|
.clear
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,8 @@ template(name="editUserPopup")
|
||||||
label
|
label
|
||||||
| {{_ 'password'}}
|
| {{_ 'password'}}
|
||||||
input.js-profile-password(type="password")
|
input.js-profile-password(type="password")
|
||||||
//div.buttonsContainer
|
div.buttonsContainer
|
||||||
// input.primary.wide(type="submit" value="{{_ 'save'}}")
|
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||||
// div
|
// div
|
||||||
// input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
|
// input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,11 @@ template(name='homeSidebar')
|
||||||
+membersWidget
|
+membersWidget
|
||||||
hr
|
hr
|
||||||
+labelsWidget
|
+labelsWidget
|
||||||
|
ul#cards.label-text-hidden
|
||||||
|
a.flex.js-toggle-minicard-label-text
|
||||||
|
span {{_ 'hide-minicard-label-text'}}
|
||||||
|
b
|
||||||
|
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
|
||||||
hr
|
hr
|
||||||
unless currentUser.isNoComments
|
unless currentUser.isNoComments
|
||||||
h3
|
h3
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ BlazeComponent.extendComponent({
|
||||||
'click .js-hide-sidebar': this.hide,
|
'click .js-hide-sidebar': this.hide,
|
||||||
'click .js-toggle-sidebar': this.toggle,
|
'click .js-toggle-sidebar': this.toggle,
|
||||||
'click .js-back-home': this.setView,
|
'click .js-back-home': this.setView,
|
||||||
|
'click .js-toggle-minicard-label-text'() {
|
||||||
|
Meteor.call('toggleMinicardLabelText');
|
||||||
|
},
|
||||||
'click .js-shortcuts'() {
|
'click .js-shortcuts'() {
|
||||||
FlowRouter.go('shortcuts');
|
FlowRouter.go('shortcuts');
|
||||||
},
|
},
|
||||||
|
|
@ -111,6 +114,12 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
Blaze.registerHelper('Sidebar', () => Sidebar);
|
Blaze.registerHelper('Sidebar', () => Sidebar);
|
||||||
|
|
||||||
|
Template.homeSidebar.helpers({
|
||||||
|
hiddenMinicardLabelText() {
|
||||||
|
return Meteor.user().hasHiddenMinicardLabelText();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
EscapeActions.register(
|
EscapeActions.register(
|
||||||
'sidebarView',
|
'sidebarView',
|
||||||
() => {
|
() => {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,83 @@ Utils = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
|
||||||
|
COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO,
|
||||||
|
processUploadedAttachment(card, fileObj, callback) {
|
||||||
|
const next = attachment => {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(attachment);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!card) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
const file = new FS.File(fileObj);
|
||||||
|
if (card.isLinkedCard()) {
|
||||||
|
file.boardId = Cards.findOne(card.linkedId).boardId;
|
||||||
|
file.cardId = card.linkedId;
|
||||||
|
} else {
|
||||||
|
file.boardId = card.boardId;
|
||||||
|
file.swimlaneId = card.swimlaneId;
|
||||||
|
file.listId = card.listId;
|
||||||
|
file.cardId = card._id;
|
||||||
|
}
|
||||||
|
file.userId = Meteor.userId();
|
||||||
|
if (file.original) {
|
||||||
|
file.original.name = fileObj.name;
|
||||||
|
}
|
||||||
|
return next(Attachments.insert(file));
|
||||||
|
},
|
||||||
|
shrinkImage(options) {
|
||||||
|
// shrink image to certain size
|
||||||
|
const dataurl = options.dataurl,
|
||||||
|
callback = options.callback,
|
||||||
|
toBlob = options.toBlob;
|
||||||
|
let canvas = document.createElement('canvas'),
|
||||||
|
image = document.createElement('img');
|
||||||
|
const maxSize = options.maxSize || 1024;
|
||||||
|
const ratio = options.ratio || 1.0;
|
||||||
|
const next = function(result) {
|
||||||
|
image = null;
|
||||||
|
canvas = null;
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
image.onload = function() {
|
||||||
|
let width = this.width,
|
||||||
|
height = this.height;
|
||||||
|
let changed = false;
|
||||||
|
if (width > height) {
|
||||||
|
if (width > maxSize) {
|
||||||
|
height *= maxSize / width;
|
||||||
|
width = maxSize;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} else if (height > maxSize) {
|
||||||
|
width *= maxSize / height;
|
||||||
|
height = maxSize;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
canvas.getContext('2d').drawImage(this, 0, 0, width, height);
|
||||||
|
if (changed === true) {
|
||||||
|
const type = 'image/jpeg';
|
||||||
|
if (toBlob) {
|
||||||
|
canvas.toBlob(next, type, ratio);
|
||||||
|
} else {
|
||||||
|
next(canvas.toDataURL(type, ratio));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next(changed);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
image.onerror = function() {
|
||||||
|
next(false);
|
||||||
|
};
|
||||||
|
image.src = dataurl;
|
||||||
|
},
|
||||||
capitalize(string) {
|
capitalize(string) {
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,10 @@ services:
|
||||||
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60
|
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60
|
||||||
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15
|
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
# ==== STORE ATTACHMENT ON SERVER FILESYSTEM INSTEAD OF MONGODB ====
|
||||||
|
# https://github.com/wekan/wekan/pull/2603
|
||||||
|
#- ATTACHMENTS_STORE_PATH = <pathname> # pathname can be relative or fullpath
|
||||||
|
#---------------------------------------------------------------
|
||||||
# ==== RICH TEXT EDITOR IN CARD COMMENTS ====
|
# ==== RICH TEXT EDITOR IN CARD COMMENTS ====
|
||||||
# https://github.com/wekan/wekan/pull/2560
|
# https://github.com/wekan/wekan/pull/2560
|
||||||
- RICHER_CARD_COMMENT_EDITOR=true
|
- RICHER_CARD_COMMENT_EDITOR=true
|
||||||
|
|
|
||||||
1449
i18n/ar.i18n.json
1449
i18n/ar.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/bg.i18n.json
1449
i18n/bg.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/br.i18n.json
1449
i18n/br.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ca.i18n.json
1449
i18n/ca.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/cs.i18n.json
1449
i18n/cs.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/da.i18n.json
1449
i18n/da.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/de.i18n.json
1449
i18n/de.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/el.i18n.json
1449
i18n/el.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/en-GB.i18n.json
1449
i18n/en-GB.i18n.json
File diff suppressed because it is too large
Load diff
|
|
@ -726,5 +726,6 @@
|
||||||
"act-duenow": "was reminding the current due (__timeValue__) of __card__ is now",
|
"act-duenow": "was reminding the current due (__timeValue__) of __card__ is now",
|
||||||
"act-atUserComment": "You were mentioned in [__board__] __card__",
|
"act-atUserComment": "You were mentioned in [__board__] __card__",
|
||||||
"delete-user-confirm-popup": "Are you sure you want to delete this account? There is no undo.",
|
"delete-user-confirm-popup": "Are you sure you want to delete this account? There is no undo.",
|
||||||
"accounts-allowUserDelete": "Allow users to self delete their account"
|
"accounts-allowUserDelete": "Allow users to self delete their account",
|
||||||
|
"hide-minicard-label-text": "Hide minicard label text"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1449
i18n/eo.i18n.json
1449
i18n/eo.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/es-AR.i18n.json
1449
i18n/es-AR.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/es.i18n.json
1449
i18n/es.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/eu.i18n.json
1449
i18n/eu.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/fa.i18n.json
1449
i18n/fa.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/fi.i18n.json
1449
i18n/fi.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/fr.i18n.json
1449
i18n/fr.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/gl.i18n.json
1449
i18n/gl.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/he.i18n.json
1449
i18n/he.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/hi.i18n.json
1449
i18n/hi.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/hu.i18n.json
1449
i18n/hu.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/hy.i18n.json
1449
i18n/hy.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/id.i18n.json
1449
i18n/id.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ig.i18n.json
1449
i18n/ig.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/it.i18n.json
1449
i18n/it.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ka.i18n.json
1449
i18n/ka.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/km.i18n.json
1449
i18n/km.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ko.i18n.json
1449
i18n/ko.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/lv.i18n.json
1449
i18n/lv.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/mk.i18n.json
1449
i18n/mk.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/mn.i18n.json
1449
i18n/mn.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/nb.i18n.json
1449
i18n/nb.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/nl.i18n.json
1449
i18n/nl.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/oc.i18n.json
1449
i18n/oc.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/pl.i18n.json
1449
i18n/pl.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/pt-BR.i18n.json
1449
i18n/pt-BR.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/pt.i18n.json
1449
i18n/pt.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ro.i18n.json
1449
i18n/ro.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ru.i18n.json
1449
i18n/ru.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/sr.i18n.json
1449
i18n/sr.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/sv.i18n.json
1449
i18n/sv.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/sw.i18n.json
1449
i18n/sw.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/ta.i18n.json
1449
i18n/ta.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/th.i18n.json
1449
i18n/th.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/tr.i18n.json
1449
i18n/tr.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/uk.i18n.json
1449
i18n/uk.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/vi.i18n.json
1449
i18n/vi.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/zh-CN.i18n.json
1449
i18n/zh-CN.i18n.json
File diff suppressed because it is too large
Load diff
1449
i18n/zh-HK.i18n.json
1449
i18n/zh-HK.i18n.json
File diff suppressed because it is too large
Load diff
|
|
@ -1,27 +1,178 @@
|
||||||
Attachments = new FS.Collection('attachments', {
|
const localFSStore = process.env.ATTACHMENTS_STORE_PATH;
|
||||||
stores: [
|
const storeName = 'attachments';
|
||||||
|
const defaultStoreOptions = {
|
||||||
|
beforeWrite: fileObj => {
|
||||||
|
if (!fileObj.isImage()) {
|
||||||
|
return {
|
||||||
|
type: 'application/octet-stream',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let store;
|
||||||
|
if (localFSStore) {
|
||||||
|
// have to reinvent methods from FS.Store.GridFS and FS.Store.FileSystem
|
||||||
|
const fs = Npm.require('fs');
|
||||||
|
const path = Npm.require('path');
|
||||||
|
const mongodb = Npm.require('mongodb');
|
||||||
|
const Grid = Npm.require('gridfs-stream');
|
||||||
|
// calulate the absolute path here, because FS.Store.FileSystem didn't expose the aboslutepath or FS.Store didn't expose api calls :(
|
||||||
|
let pathname = localFSStore;
|
||||||
|
/*eslint camelcase: ["error", {allow: ["__meteor_bootstrap__"]}] */
|
||||||
|
|
||||||
|
if (!pathname && __meteor_bootstrap__ && __meteor_bootstrap__.serverDir) {
|
||||||
|
pathname = path.join(
|
||||||
|
__meteor_bootstrap__.serverDir,
|
||||||
|
`../../../cfs/files/${storeName}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pathname)
|
||||||
|
throw new Error('FS.Store.FileSystem unable to determine path');
|
||||||
|
|
||||||
|
// Check if we have '~/foo/bar'
|
||||||
|
if (pathname.split(path.sep)[0] === '~') {
|
||||||
|
const homepath =
|
||||||
|
process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
|
||||||
|
if (homepath) {
|
||||||
|
pathname = pathname.replace('~', homepath);
|
||||||
|
} else {
|
||||||
|
throw new Error('FS.Store.FileSystem unable to resolve "~" in path');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set absolute path
|
||||||
|
const absolutePath = path.resolve(pathname);
|
||||||
|
|
||||||
|
const _FStore = new FS.Store.FileSystem(storeName, {
|
||||||
|
path: localFSStore,
|
||||||
|
...defaultStoreOptions,
|
||||||
|
});
|
||||||
|
const GStore = {
|
||||||
|
fileKey(fileObj) {
|
||||||
|
const key = {
|
||||||
|
_id: null,
|
||||||
|
filename: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we're passed a fileObj, we retrieve the _id and filename from it.
|
||||||
|
if (fileObj) {
|
||||||
|
const info = fileObj._getInfo(storeName, {
|
||||||
|
updateFileRecordFirst: false,
|
||||||
|
});
|
||||||
|
key._id = info.key || null;
|
||||||
|
key.filename =
|
||||||
|
info.name ||
|
||||||
|
fileObj.name({ updateFileRecordFirst: false }) ||
|
||||||
|
`${fileObj.collectionName}-${fileObj._id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If key._id is null at this point, createWriteStream will let GridFS generate a new ID
|
||||||
|
return key;
|
||||||
|
},
|
||||||
|
db: undefined,
|
||||||
|
mongoOptions: { useNewUrlParser: true },
|
||||||
|
mongoUrl: process.env.MONGO_URL,
|
||||||
|
init() {
|
||||||
|
this._init(err => {
|
||||||
|
this.inited = !err;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_init(callback) {
|
||||||
|
const self = this;
|
||||||
|
mongodb.MongoClient.connect(self.mongoUrl, self.mongoOptions, function(
|
||||||
|
err,
|
||||||
|
db,
|
||||||
|
) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
self.db = db;
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
createReadStream(fileKey, options) {
|
||||||
|
const self = this;
|
||||||
|
if (!self.inited) {
|
||||||
|
self.init();
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// Init GridFS
|
||||||
|
const gfs = new Grid(self.db, mongodb);
|
||||||
|
|
||||||
|
// Set the default streamning settings
|
||||||
|
const settings = {
|
||||||
|
_id: new mongodb.ObjectID(fileKey._id),
|
||||||
|
root: `cfs_gridfs.${storeName}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if this should be a partial read
|
||||||
|
if (
|
||||||
|
typeof options.start !== 'undefined' &&
|
||||||
|
typeof options.end !== 'undefined'
|
||||||
|
) {
|
||||||
|
// Add partial info
|
||||||
|
settings.range = {
|
||||||
|
startPos: options.start,
|
||||||
|
endPos: options.end,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return gfs.createReadStream(settings);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
GStore.init();
|
||||||
|
const CRS = 'createReadStream';
|
||||||
|
const _CRS = `_${CRS}`;
|
||||||
|
const FStore = _FStore._transform;
|
||||||
|
FStore[_CRS] = FStore[CRS].bind(FStore);
|
||||||
|
FStore[CRS] = function(fileObj, options) {
|
||||||
|
let stream;
|
||||||
|
try {
|
||||||
|
const localFile = path.join(
|
||||||
|
absolutePath,
|
||||||
|
FStore.storage.fileKey(fileObj),
|
||||||
|
);
|
||||||
|
const state = fs.statSync(localFile);
|
||||||
|
if (state) {
|
||||||
|
stream = FStore[_CRS](fileObj, options);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// file is not there, try GridFS ?
|
||||||
|
stream = undefined;
|
||||||
|
}
|
||||||
|
if (stream) return stream;
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
const stream = GStore[CRS](GStore.fileKey(fileObj), options);
|
||||||
|
return stream;
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(FStore);
|
||||||
|
store = _FStore;
|
||||||
|
} else {
|
||||||
|
store = new FS.Store.GridFS(localFSStore ? `G${storeName}` : storeName, {
|
||||||
// XXX Add a new store for cover thumbnails so we don't load big images in
|
// XXX Add a new store for cover thumbnails so we don't load big images in
|
||||||
// the general board view
|
// the general board view
|
||||||
new FS.Store.GridFS('attachments', {
|
// If the uploaded document is not an image we need to enforce browser
|
||||||
// If the uploaded document is not an image we need to enforce browser
|
// download instead of execution. This is particularly important for HTML
|
||||||
// download instead of execution. This is particularly important for HTML
|
// files that the browser will just execute if we don't serve them with the
|
||||||
// files that the browser will just execute if we don't serve them with the
|
// appropriate `application/octet-stream` MIME header which can lead to user
|
||||||
// appropriate `application/octet-stream` MIME header which can lead to user
|
// data leaks. I imagine other formats (like PDF) can also be attack vectors.
|
||||||
// data leaks. I imagine other formats (like PDF) can also be attack vectors.
|
// See https://github.com/wekan/wekan/issues/99
|
||||||
// See https://github.com/wekan/wekan/issues/99
|
// XXX Should we use `beforeWrite` option of CollectionFS instead of
|
||||||
// XXX Should we use `beforeWrite` option of CollectionFS instead of
|
// collection-hooks?
|
||||||
// collection-hooks?
|
// We should use `beforeWrite`.
|
||||||
// We should use `beforeWrite`.
|
...defaultStoreOptions,
|
||||||
beforeWrite: fileObj => {
|
});
|
||||||
if (!fileObj.isImage()) {
|
}
|
||||||
return {
|
Attachments = new FS.Collection('attachments', {
|
||||||
type: 'application/octet-stream',
|
stores: [store],
|
||||||
};
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Meteor.isServer) {
|
if (Meteor.isServer) {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,14 @@ Users.attachSchema(
|
||||||
},
|
},
|
||||||
'profile.hiddenSystemMessages': {
|
'profile.hiddenSystemMessages': {
|
||||||
/**
|
/**
|
||||||
* does the user wants to hide system messages?
|
* does the user want to hide system messages?
|
||||||
|
*/
|
||||||
|
type: Boolean,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
'profile.hiddenMinicardLabelText': {
|
||||||
|
/**
|
||||||
|
* does the user want to hide minicard label texts?
|
||||||
*/
|
*/
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
optional: true,
|
optional: true,
|
||||||
|
|
@ -253,7 +260,7 @@ Users.attachSchema(
|
||||||
Users.allow({
|
Users.allow({
|
||||||
update(userId) {
|
update(userId) {
|
||||||
const user = Users.findOne(userId);
|
const user = Users.findOne(userId);
|
||||||
return user && Meteor.user().isAdmin;
|
return user; // && Meteor.user().isAdmin; // GitHub issue #2590
|
||||||
},
|
},
|
||||||
remove(userId, doc) {
|
remove(userId, doc) {
|
||||||
const adminsNumber = Users.find({ isAdmin: true }).count();
|
const adminsNumber = Users.find({ isAdmin: true }).count();
|
||||||
|
|
@ -359,6 +366,11 @@ Users.helpers({
|
||||||
return profile.hiddenSystemMessages || false;
|
return profile.hiddenSystemMessages || false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hasHiddenMinicardLabelText() {
|
||||||
|
const profile = this.profile || {};
|
||||||
|
return profile.hiddenMinicardLabelText || false;
|
||||||
|
},
|
||||||
|
|
||||||
getEmailBuffer() {
|
getEmailBuffer() {
|
||||||
const { emailBuffer = [] } = this.profile || {};
|
const { emailBuffer = [] } = this.profile || {};
|
||||||
return emailBuffer;
|
return emailBuffer;
|
||||||
|
|
@ -462,6 +474,14 @@ Users.mutations({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleLabelText(value = false) {
|
||||||
|
return {
|
||||||
|
$set: {
|
||||||
|
'profile.hiddenMinicardLabelText': !value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
addNotification(activityId) {
|
addNotification(activityId) {
|
||||||
return {
|
return {
|
||||||
$addToSet: {
|
$addToSet: {
|
||||||
|
|
@ -525,6 +545,10 @@ Meteor.methods({
|
||||||
const user = Meteor.user();
|
const user = Meteor.user();
|
||||||
user.toggleSystem(user.hasHiddenSystemMessages());
|
user.toggleSystem(user.hasHiddenSystemMessages());
|
||||||
},
|
},
|
||||||
|
toggleMinicardLabelText() {
|
||||||
|
const user = Meteor.user();
|
||||||
|
user.toggleLabelText(user.hasHiddenMinicardLabelText());
|
||||||
|
},
|
||||||
changeLimitToShowCardsCount(limit) {
|
changeLimitToShowCardsCount(limit) {
|
||||||
check(limit, Number);
|
check(limit, Number);
|
||||||
Meteor.user().setShowCardsCountAt(limit);
|
Meteor.user().setShowCardsCountAt(limit);
|
||||||
|
|
@ -946,8 +970,8 @@ if (Meteor.isServer) {
|
||||||
if (Meteor.isServer) {
|
if (Meteor.isServer) {
|
||||||
// Middleware which checks that API is enabled.
|
// Middleware which checks that API is enabled.
|
||||||
JsonRoutes.Middleware.use(function(req, res, next) {
|
JsonRoutes.Middleware.use(function(req, res, next) {
|
||||||
const api = req.url.search('api');
|
const api = req.url.startsWith('/api');
|
||||||
if ((api === 1 && process.env.WITH_API === 'true') || api === -1) {
|
if ((api === true && process.env.WITH_API === 'true') || api === false) {
|
||||||
return next();
|
return next();
|
||||||
} else {
|
} else {
|
||||||
res.writeHead(301, { Location: '/' });
|
res.writeHead(301, { Location: '/' });
|
||||||
|
|
|
||||||
4973
package-lock.json
generated
4973
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "wekan",
|
"name": "wekan",
|
||||||
"version": "v3.08.0",
|
"version": "v3.15.0",
|
||||||
"description": "Open-Source kanban",
|
"description": "Open-Source kanban",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -55,12 +55,15 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.5.4",
|
"@babel/runtime": "^7.5.4",
|
||||||
"ajv": "^5.0.0",
|
"ajv": "^5.0.0",
|
||||||
|
"babel-runtime": "^6.26.0",
|
||||||
"bcrypt": "^3.0.2",
|
"bcrypt": "^3.0.2",
|
||||||
"bson": "^4.0.0",
|
"bson": "^4.0.0",
|
||||||
"bunyan": "^1.8.12",
|
"bunyan": "^1.8.12",
|
||||||
"es6-promise": "^4.2.4",
|
"es6-promise": "^4.2.4",
|
||||||
|
"gridfs-stream": "^0.5.3",
|
||||||
"ldapjs": "^1.0.2",
|
"ldapjs": "^1.0.2",
|
||||||
"meteor-node-stubs": "^0.4.1",
|
"meteor-node-stubs": "^0.4.1",
|
||||||
|
"mongodb": "^2.2.19",
|
||||||
"os": "^0.1.1",
|
"os": "^0.1.1",
|
||||||
"page": "^1.8.6",
|
"page": "^1.8.6",
|
||||||
"qs": "^6.5.2",
|
"qs": "^6.5.2",
|
||||||
|
|
|
||||||
|
|
@ -1524,7 +1524,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||||
<ul class="toc-list-h1">
|
<ul class="toc-list-h1">
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v3.08">Wekan REST API v3.08</a>
|
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v3.11">Wekan REST API v3.11</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
@ -2017,7 +2017,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="dark-box"></div>
|
<div class="dark-box"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1 id="wekan-rest-api">Wekan REST API v3.08</h1>
|
<h1 id="wekan-rest-api">Wekan REST API v3.11</h1>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.</p>
|
<p>Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
swagger: '2.0'
|
swagger: '2.0'
|
||||||
info:
|
info:
|
||||||
title: Wekan REST API
|
title: Wekan REST API
|
||||||
version: v3.08
|
version: v3.11
|
||||||
description: |
|
description: |
|
||||||
The REST API allows you to control and extend Wekan with ease.
|
The REST API allows you to control and extend Wekan with ease.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
cd ~/repos/wekan
|
cd ~/repos/wekan
|
||||||
./releases/rebuild-release.sh
|
./releases/rebuild-release.sh
|
||||||
./releases/delete-phantomjs.sh
|
#./releases/delete-phantomjs.sh
|
||||||
cd ~/repos/wekan/.build
|
cd ~/repos/wekan/.build
|
||||||
zip -r wekan-$1.zip bundle
|
zip -r wekan-$1.zip bundle
|
||||||
scp wekan-$1.zip x2:/var/snap/wekan/common/releases.wekan.team/
|
scp wekan-$1.zip x2:/var/snap/wekan/common/releases.wekan.team/
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
# Usage: ./release.sh 1.36
|
# Usage: ./release.sh 1.36
|
||||||
|
|
||||||
# Delete old stuff
|
# Delete old stuff
|
||||||
cd ~/repos/wekan
|
#cd ~/repos/wekan
|
||||||
./releases/release-cleanup.sh
|
#./releases/release-cleanup.sh
|
||||||
|
|
||||||
# Build Source
|
# Build Source
|
||||||
cd ~/repos/wekan
|
#cd ~/repos/wekan
|
||||||
./releases/rebuild-release.sh
|
#./releases/rebuild-release.sh
|
||||||
|
|
||||||
# Build Sandstorm
|
# Build Sandstorm
|
||||||
cd ~/repos/wekan
|
cd ~/repos/wekan
|
||||||
|
|
@ -16,6 +16,6 @@ scp wekan-$1.spk x2:/var/snap/wekan/common/releases.wekan.team/
|
||||||
mv wekan-$1.spk ..
|
mv wekan-$1.spk ..
|
||||||
|
|
||||||
# Delete old stuff
|
# Delete old stuff
|
||||||
cd ~/repos/wekan
|
#cd ~/repos/wekan
|
||||||
./releases/release-cleanup.sh
|
#./releases/release-cleanup.sh
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
# Usage: ./release.sh 1.36
|
# Usage: ./release.sh 1.36
|
||||||
|
|
||||||
|
# Build Bundle
|
||||||
|
~/repos/wekan/releases/release-bundle.sh $1
|
||||||
|
|
||||||
# Build Sandstorm
|
# Build Sandstorm
|
||||||
./release-sandstorm.sh $1
|
~/repos/wekan/release-sandstorm.sh $1
|
||||||
|
|
||||||
# Build Snap
|
# Build Snap
|
||||||
./release-snap.sh $1
|
#./release-snap.sh $1
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
|
||||||
appTitle = (defaultText = "Wekan"),
|
appTitle = (defaultText = "Wekan"),
|
||||||
# The name of the app as it is displayed to the user.
|
# The name of the app as it is displayed to the user.
|
||||||
|
|
||||||
appVersion = 310,
|
appVersion = 317,
|
||||||
# Increment this for every release.
|
# Increment this for every release.
|
||||||
|
|
||||||
appMarketingVersion = (defaultText = "3.08.0~2019-08-07"),
|
appMarketingVersion = (defaultText = "3.15.0~2019-08-11"),
|
||||||
# Human-readable presentation of the app version.
|
# Human-readable presentation of the app version.
|
||||||
|
|
||||||
minUpgradableAppVersion = 0,
|
minUpgradableAppVersion = 0,
|
||||||
|
|
|
||||||
6
server/richer-editor-setting-helper.js
Normal file
6
server/richer-editor-setting-helper.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Meteor.startup(() => {
|
||||||
|
const RCCE = process.env.RICHER_CARD_COMMENT_EDITOR;
|
||||||
|
if (RCCE) {
|
||||||
|
Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR = RCCE !== 'false';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
# All supported keys are defined here together with descriptions and default values
|
# All supported keys are defined here together with descriptions and default values
|
||||||
|
|
||||||
# list of supported keys
|
# list of supported keys
|
||||||
keys="DEBUG MONGO_URL MONGODB_BIND_UNIX_SOCKET MONGO_URL MONGODB_BIND_IP MONGODB_PORT MAIL_URL MAIL_FROM ROOT_URL PORT DISABLE_MONGODB CADDY_ENABLED CADDY_BIND_PORT WITH_API RICHER_CARD_COMMENT_EDITOR ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW MAX_IMAGE_PIXEL IMAGE_COMPRESS_RATIO BIGEVENTS_PATTERN NOTIFY_DUE_DAYS_BEFORE_AND_AFTER NOTIFY_DUE_AT_HOUR_OF_DAY EMAIL_NOTIFICATION_TIMEOUT CORS CORS_ALLOW_HEADERS CORS_EXPOSE_HEADERS MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_ENABLED OAUTH2_LOGIN_STYLE OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT OAUTH2_ID_MAP OAUTH2_USERNAME_MAP OAUTH2_FULLNAME_MAP OAUTH2_ID_TOKEN_WHITELIST_FIELDS OAUTH2_EMAIL_MAP OAUTH2_REQUEST_PERMISSIONS LDAP_ENABLE LDAP_PORT LDAP_HOST LDAP_BASEDN LDAP_LOGIN_FALLBACK LDAP_RECONNECT LDAP_TIMEOUT LDAP_IDLE_TIMEOUT LDAP_CONNECT_TIMEOUT LDAP_AUTHENTIFICATION LDAP_AUTHENTIFICATION_USERDN LDAP_AUTHENTIFICATION_PASSWORD LDAP_LOG_ENABLED LDAP_BACKGROUND_SYNC LDAP_BACKGROUND_SYNC_INTERVAL LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS LDAP_ENCRYPTION LDAP_CA_CERT LDAP_REJECT_UNAUTHORIZED LDAP_USER_AUTHENTICATION LDAP_USER_AUTHENTICATION_FIELD LDAP_USER_SEARCH_FILTER LDAP_USER_SEARCH_SCOPE LDAP_USER_SEARCH_FIELD LDAP_SEARCH_PAGE_SIZE LDAP_SEARCH_SIZE_LIMIT LDAP_GROUP_FILTER_ENABLE LDAP_GROUP_FILTER_OBJECTCLASS LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT LDAP_GROUP_FILTER_GROUP_NAME LDAP_UNIQUE_IDENTIFIER_FIELD LDAP_UTF8_NAMES_SLUGIFY LDAP_USERNAME_FIELD LDAP_FULLNAME_FIELD LDAP_MERGE_EXISTING_USERS LDAP_SYNC_USER_DATA LDAP_SYNC_USER_DATA_FIELDMAP LDAP_SYNC_GROUP_ROLES LDAP_DEFAULT_DOMAIN LDAP_EMAIL_MATCH_ENABLE LDAP_EMAIL_MATCH_REQUIRE LDAP_EMAIL_MATCH_VERIFIED LDAP_EMAIL_FIELD LDAP_SYNC_ADMIN_STATUS LDAP_SYNC_ADMIN_GROUPS HEADER_LOGIN_ID HEADER_LOGIN_FIRSTNAME HEADER_LOGIN_LASTNAME HEADER_LOGIN_EMAIL LOGOUT_WITH_TIMER LOGOUT_IN LOGOUT_ON_HOURS LOGOUT_ON_MINUTES DEFAULT_AUTHENTICATION_METHOD"
|
keys="DEBUG MONGO_URL MONGODB_BIND_UNIX_SOCKET MONGO_URL MONGODB_BIND_IP MONGODB_PORT MAIL_URL MAIL_FROM ROOT_URL PORT DISABLE_MONGODB CADDY_ENABLED CADDY_BIND_PORT WITH_API RICHER_CARD_COMMENT_EDITOR ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW MAX_IMAGE_PIXEL IMAGE_COMPRESS_RATIO BIGEVENTS_PATTERN NOTIFY_DUE_DAYS_BEFORE_AND_AFTER NOTIFY_DUE_AT_HOUR_OF_DAY EMAIL_NOTIFICATION_TIMEOUT CORS CORS_ALLOW_HEADERS CORS_EXPOSE_HEADERS MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_ENABLED OAUTH2_LOGIN_STYLE OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT OAUTH2_ID_MAP OAUTH2_USERNAME_MAP OAUTH2_FULLNAME_MAP OAUTH2_ID_TOKEN_WHITELIST_FIELDS OAUTH2_EMAIL_MAP OAUTH2_REQUEST_PERMISSIONS LDAP_ENABLE LDAP_PORT LDAP_HOST LDAP_BASEDN LDAP_LOGIN_FALLBACK LDAP_RECONNECT LDAP_TIMEOUT LDAP_IDLE_TIMEOUT LDAP_CONNECT_TIMEOUT LDAP_AUTHENTIFICATION LDAP_AUTHENTIFICATION_USERDN LDAP_AUTHENTIFICATION_PASSWORD LDAP_LOG_ENABLED LDAP_BACKGROUND_SYNC LDAP_BACKGROUND_SYNC_INTERVAL LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS LDAP_ENCRYPTION LDAP_CA_CERT LDAP_REJECT_UNAUTHORIZED LDAP_USER_AUTHENTICATION LDAP_USER_AUTHENTICATION_FIELD LDAP_USER_SEARCH_FILTER LDAP_USER_SEARCH_SCOPE LDAP_USER_SEARCH_FIELD LDAP_SEARCH_PAGE_SIZE LDAP_SEARCH_SIZE_LIMIT LDAP_GROUP_FILTER_ENABLE LDAP_GROUP_FILTER_OBJECTCLASS LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT LDAP_GROUP_FILTER_GROUP_NAME LDAP_UNIQUE_IDENTIFIER_FIELD LDAP_UTF8_NAMES_SLUGIFY LDAP_USERNAME_FIELD LDAP_FULLNAME_FIELD LDAP_MERGE_EXISTING_USERS LDAP_SYNC_USER_DATA LDAP_SYNC_USER_DATA_FIELDMAP LDAP_SYNC_GROUP_ROLES LDAP_DEFAULT_DOMAIN LDAP_EMAIL_MATCH_ENABLE LDAP_EMAIL_MATCH_REQUIRE LDAP_EMAIL_MATCH_VERIFIED LDAP_EMAIL_FIELD LDAP_SYNC_ADMIN_STATUS LDAP_SYNC_ADMIN_GROUPS HEADER_LOGIN_ID HEADER_LOGIN_FIRSTNAME HEADER_LOGIN_LASTNAME HEADER_LOGIN_EMAIL LOGOUT_WITH_TIMER LOGOUT_IN LOGOUT_ON_HOURS LOGOUT_ON_MINUTES DEFAULT_AUTHENTICATION_METHOD ATTACHMENTS_STORE_PATH"
|
||||||
|
|
||||||
# default values
|
# default values
|
||||||
DESCRIPTION_DEBUG="Debug OIDC OAuth2 etc. Example: sudo snap set wekan debug='true'"
|
DESCRIPTION_DEBUG="Debug OIDC OAuth2 etc. Example: sudo snap set wekan debug='true'"
|
||||||
|
|
@ -88,6 +88,10 @@ DESCRIPTION_ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW="Accounts lockout unkn
|
||||||
DEFAULT_ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW="15"
|
DEFAULT_ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW="15"
|
||||||
KEY_ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW="accounts-lockout-unknown-users-failure-window"
|
KEY_ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW="accounts-lockout-unknown-users-failure-window"
|
||||||
|
|
||||||
|
DESCRIPTION_ATTACHMENTS_STORE_PATH="Allow wekan ower to specify where uploaded files to store on the server instead of the mongodb"
|
||||||
|
DEFAULT_ATTACHMENTS_STORE_PATH=""
|
||||||
|
KEY_ATTACHMENTS_STORE_PATH="attachments-store-path"
|
||||||
|
|
||||||
DESCRIPTION_MAX_IMAGE_PIXEL="Max image pixel: Allow to shrink attached/pasted image https://github.com/wekan/wekan/pull/2544"
|
DESCRIPTION_MAX_IMAGE_PIXEL="Max image pixel: Allow to shrink attached/pasted image https://github.com/wekan/wekan/pull/2544"
|
||||||
DEFAULT_MAX_IMAGE_PIXEL=""
|
DEFAULT_MAX_IMAGE_PIXEL=""
|
||||||
KEY_MAX_IMAGE_PIXEL="max-image-pixel"
|
KEY_MAX_IMAGE_PIXEL="max-image-pixel"
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,12 @@ echo -e "\t$ snap set $SNAP_NAME image-compress-ratio='80'"
|
||||||
echo -e "Disabled:"
|
echo -e "Disabled:"
|
||||||
echo -e "\t$ snap set $SNAP_NAME image-compress-ratio=''"
|
echo -e "\t$ snap set $SNAP_NAME image-compress-ratio=''"
|
||||||
echo -e "\n"
|
echo -e "\n"
|
||||||
|
echo -e "Allow to set attachment upload into specified server location. Create that directory first. https://github.com/wekan/wekan/pull/2603"
|
||||||
|
echo -e "Example:"
|
||||||
|
echo -e "\t$ snap set $SNAP_NAME attachments-store-path='/var/snap/wekan/common/attachments'"
|
||||||
|
echo -e "Disabled:"
|
||||||
|
echo -e "\t$ snap set $SNAP_NAME attachments-store-path=''"
|
||||||
|
echo -e "\n"
|
||||||
echo -e "BIGEVENTS DUE ETC NOTIFICATIONS https://github.com/wekan/wekan/pull/2541"
|
echo -e "BIGEVENTS DUE ETC NOTIFICATIONS https://github.com/wekan/wekan/pull/2541"
|
||||||
echo -e "Big events pattern: Notify always due etc regardless of notification settings. Default: due, All: received|start|due|end, Disabled: NONE"
|
echo -e "Big events pattern: Notify always due etc regardless of notification settings. Default: due, All: received|start|due|end, Disabled: NONE"
|
||||||
echo -e "Default:"
|
echo -e "Default:"
|
||||||
|
|
|
||||||
|
|
@ -104,11 +104,11 @@ parts:
|
||||||
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
|
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
|
||||||
# Delete meteor 1.8.x dependencies and
|
# Delete meteor 1.8.x dependencies and
|
||||||
# move Snap's working meteor 1.6.0.1 dependencies to be used at Wekan Snap
|
# move Snap's working meteor 1.6.0.1 dependencies to be used at Wekan Snap
|
||||||
rm -rf .meteor
|
#rm -rf .meteor
|
||||||
mv .meteor-1.6-snap/.meteor .
|
#mv .meteor-1.6-snap/.meteor .
|
||||||
mv .meteor-1.6-snap/package.json .
|
#mv .meteor-1.6-snap/package.json .
|
||||||
mv .meteor-1.6-snap/package-lock.json .
|
#mv .meteor-1.6-snap/package-lock.json .
|
||||||
mv .meteor-1.6-snap/rebuild-wekan.sh .
|
#mv .meteor-1.6-snap/rebuild-wekan.sh .
|
||||||
rm -rf .meteor-1.6-snap
|
rm -rf .meteor-1.6-snap
|
||||||
# Create the OpenAPI specification
|
# Create the OpenAPI specification
|
||||||
rm -rf .build
|
rm -rf .build
|
||||||
|
|
@ -201,6 +201,7 @@ parts:
|
||||||
rm -rf package-lock.json .build
|
rm -rf package-lock.json .build
|
||||||
meteor add standard-minifier-js --allow-superuser
|
meteor add standard-minifier-js --allow-superuser
|
||||||
meteor npm install --allow-superuser
|
meteor npm install --allow-superuser
|
||||||
|
meteor npm install --allow-superuser --save babel-runtime
|
||||||
meteor build .build --directory --allow-superuser
|
meteor build .build --directory --allow-superuser
|
||||||
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
|
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
|
||||||
#Removed binary version of bcrypt because of security vulnerability that is not fixed yet.
|
#Removed binary version of bcrypt because of security vulnerability that is not fixed yet.
|
||||||
|
|
@ -214,15 +215,20 @@ parts:
|
||||||
# Change to directory .build/bundle/programs/server
|
# Change to directory .build/bundle/programs/server
|
||||||
cd .build/bundle/programs/server
|
cd .build/bundle/programs/server
|
||||||
npm install
|
npm install
|
||||||
|
npm install --allow-superuser --save babel-runtime
|
||||||
#meteor npm install --save bcrypt
|
#meteor npm install --save bcrypt
|
||||||
# Change back to Wekan source directory
|
# Change back to Wekan source directory
|
||||||
cd ../../../..
|
cd ../../../..
|
||||||
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
|
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
|
||||||
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
|
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
|
||||||
rm $SNAPCRAFT_PART_INSTALL/lib/node_modules/wekan
|
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/wekan
|
||||||
rm $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
|
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
|
||||||
rm $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/tar/lib/.mkdir.js.swp
|
||||||
rm $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-gyp/node_modules/tar/lib/.mkdir.js.swp
|
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||||
|
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||||
|
# Meteor 1.8.x additional .swp remove
|
||||||
|
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||||
|
|
||||||
organize:
|
organize:
|
||||||
README: README.wekan
|
README: README.wekan
|
||||||
prime:
|
prime:
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ cd /home/wekan/app_build/bundle/programs/server/
|
||||||
sudo npm install
|
sudo npm install
|
||||||
sudo chown -R wekan:wekan ./node_modules
|
sudo chown -R wekan:wekan ./node_modules
|
||||||
|
|
||||||
cd /home/wekan/app_build/bundle
|
#cd /home/wekan/app_build/bundle
|
||||||
find . -name "*phantomjs*" | sudo xargs rm -rf
|
#find . -name "*phantomjs*" | sudo xargs rm -rf
|
||||||
|
|
||||||
sudo mv /home/wekan/app_build/bundle /build
|
sudo mv /home/wekan/app_build/bundle /build
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue