This commit is contained in:
Romulus Urakagi Tsai 2019-08-12 01:43:21 +00:00
commit efdab37f3f
87 changed files with 35503 additions and 44501 deletions

3
.gitignore vendored
View file

@ -29,3 +29,6 @@ versions.json
Thumbs.db
ehthumbs.db
.eslintcache
package-lock.json
.meteor/local
.meteor-1.6-snap/.meteor/local

View file

@ -91,3 +91,8 @@ mdg:meteor-apm-agent
meteorhacks:unblock
lucasantoniassi:accounts-lockout
wekan-markdown
konecty:mongo-counter
percolate:synced-cron
easylogic:summernote
cfs:filesystem

View file

@ -30,6 +30,7 @@ cfs:collection@0.5.5
cfs:collection-filters@0.2.4
cfs:data-man@0.0.6
cfs:file@0.1.17
cfs:filesystem@0.1.2
cfs:gridfs@0.0.34
cfs:http-methods@0.0.32
cfs:http-publish@0.0.13
@ -55,6 +56,7 @@ ddp-server@2.1.1
deps@1.0.12
diff-sequence@1.0.7
dynamic-import@0.2.1
easylogic:summernote@0.8.8
ecmascript@0.9.0
ecmascript-runtime@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:flow-router@2.12.1
kenton:accounts-sandstorm@0.7.0
konecty:mongo-counter@0.0.5_3
lamhieu:meteorx@2.0.1
launch-screen@1.1.1
livedata@1.0.18
@ -170,6 +173,7 @@ templating-compiler@1.3.3
templating-runtime@1.3.2
templating-tools@1.1.2
tracker@1.1.3
twbs:bootstrap@3.3.6
ui@1.0.13
underscore@1.0.10
url@1.1.0

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "wekan",
"version": "v3.08.0",
"version": "v3.15.0",
"description": "Open-Source kanban",
"private": true,
"scripts": {
@ -53,16 +53,21 @@
"prettier-eslint": "^8.8.2"
},
"dependencies": {
"@babel/runtime": "^7.1.2",
"@babel/runtime": "^7.5.4",
"ajv": "^5.0.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",
"hoek": "^5.0.4",
"gridfs-stream": "^0.5.3",
"ldapjs": "^1.0.2",
"meteor-node-stubs": "^0.4.1",
"mongodb": "^2.2.19",
"os": "^0.1.1",
"page": "^1.8.6",
"qs": "^6.5.2",
"source-map-support": "^0.5.9",
"source-map-support": "^0.5.12",
"xss": "^1.0.6"
}
}

View file

@ -95,3 +95,4 @@ wekan-markdown
konecty:mongo-counter
percolate:synced-cron
easylogic:summernote
cfs:filesystem

View file

@ -30,6 +30,7 @@ cfs:collection@0.5.5
cfs:collection-filters@0.2.4
cfs:data-man@0.0.6
cfs:file@0.1.17
cfs:filesystem@0.1.2
cfs:gridfs@0.0.34
cfs:http-methods@0.0.32
cfs:http-publish@0.0.13

View file

@ -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
This release fixes the following bugs:

View file

@ -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_FAILURE_WINDOW=15 \
RICHER_CARD_COMMENT_EDITOR=true \
ATTACHMENTS_STORE_PATH="" \
MAX_IMAGE_PIXEL="" \
IMAGE_COMPRESS_RATIO="" \
BIGEVENTS_PATTERN="" \
@ -259,8 +260,8 @@ RUN \
#gosu wekan:wekan npm install bcrypt && \
#
# Delete phantomjs
cd /home/wekan/app_build/bundle && \
find . -name "*phantomjs*" | xargs rm -rf && \
#cd /home/wekan/app_build/bundle && \
#find . -name "*phantomjs*" | xargs rm -rf && \
#
cd /home/wekan/app_build/bundle/programs/server/ && \
gosu wekan:wekan npm install && \

View file

@ -1,5 +1,5 @@
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
appVersion: "v3.08.0"
appVersion: "v3.15.0"
files:
userUploads:
- README.md

View file

@ -38,6 +38,7 @@ BlazeComponent.extendComponent({
resetCommentInput(input);
Tracker.flush();
autosize.update(input);
input.trigger('submitted');
}
evt.preventDefault();
},
@ -54,7 +55,7 @@ BlazeComponent.extendComponent({
// XXX This should be a static method of the `commentForm` component
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();
commentFormIsOpen.set(false);
}

View file

@ -31,12 +31,28 @@ template(name="boardList")
i.fa.js-has-spenttime-cards(
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}}")
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
unless isMiniScreen
if isSandstorm
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.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")
h1 {{_ 'my-boards'}}

View file

@ -8,10 +8,10 @@ Template.boardListHeaderBar.events({
Template.boardListHeaderBar.helpers({
templatesBoardId() {
return Meteor.user().getTemplatesBoardId();
return Meteor.user() && Meteor.user().getTemplatesBoardId();
},
templatesBoardSlug() {
return Meteor.user().getTemplatesBoardSlug();
return Meteor.user() && Meteor.user().getTemplatesBoardSlug();
},
});

View file

@ -55,24 +55,12 @@ Template.cardAttachmentsPopup.events({
'change .js-attach-file'(event) {
const card = this;
const processFile = f => {
const file = new FS.File(f);
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();
const attachment = Attachments.insert(file);
if (attachment && attachment._id && attachment.isImage()) {
card.setCover(attachment._id);
}
Popup.close();
Utils.processUploadedAttachment(card, f, attachment => {
if (attachment && attachment._id && attachment.isImage()) {
card.setCover(attachment._id);
}
Popup.close();
});
};
FS.Utility.eachFile(event, f => {
@ -86,7 +74,7 @@ Template.cardAttachmentsPopup.events({
reader.onload = function(e) {
const dataurl = e && e.target && e.target.result;
if (dataurl !== undefined) {
shrinkImage({
Utils.shrinkImage({
dataurl,
maxSize: MAX_IMAGE_PIXEL,
ratio: COMPRESS_RATIO,
@ -118,59 +106,9 @@ Template.cardAttachmentsPopup.events({
'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});
const MAX_IMAGE_PIXEL = Meteor.settings.public.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Meteor.settings.public.IMAGE_COMPRESS_RATIO;
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
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(() => {
// we can paste image from clipboard
@ -182,7 +120,7 @@ Template.previewClipboardImagePopup.onRendered(() => {
};
if (MAX_IMAGE_PIXEL) {
// if has size limitation on image we shrink it before uploading
shrinkImage({
Utils.shrinkImage({
dataurl: results.dataURL,
maxSize: MAX_IMAGE_PIXEL,
ratio: COMPRESS_RATIO,

View file

@ -8,9 +8,12 @@ template(name="minicard")
if labels
.minicard-labels
each labels
span.card-label(class="card-label-{{color}}" title=name)
+viewer
= name
unless hiddenMinicardLabelText
span.card-label(class="card-label-{{color}}" title=name)
+viewer
= name
if hiddenMinicardLabelText
.minicard-label(class="card-label-{{color}}" title="{{name}}")
.minicard-title
.handle
.fa.fa-arrows

View file

@ -16,6 +16,17 @@ BlazeComponent.extendComponent({
Utils.goBoardId(this.data().linkedId);
},
},
{
'click .js-toggle-minicard-label-text'() {
Meteor.call('toggleMinicardLabelText');
},
},
];
},
}).register('minicard');
Template.minicard.helpers({
hiddenMinicardLabelText() {
return Meteor.user().hasHiddenMinicardLabelText();
},
});

View file

@ -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(() => {
const textareaSelector = 'textarea';
const enableRicherEditor =
Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR || true;
const mentions = [
// User mentions
{
@ -32,7 +102,7 @@ Template.editor.onRendered(() => {
autosize($textarea);
$textarea.escapeableTextComplete(mentions);
};
if (enableRicherEditor) {
if (Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR !== false) {
const isSmall = Utils.isMiniScreen();
const toolbar = isSmall
? [
@ -50,47 +120,11 @@ Template.editor.onRendered(() => {
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['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 :(
['view', ['fullscreen', 'help']],
];
const cleanPastedHTML = function(input) {
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 cleanPastedHTML = sanitizeXss;
const editor = '.editor';
const selectors = [
`.js-new-comment-form ${editor}`,
@ -116,8 +150,8 @@ Template.editor.onRendered(() => {
callbacks: {
onInit(object) {
const originalInput = this;
$(originalInput).on('input', function() {
// when comment is submitted, the original textarea will be set to '', so shall we
$(originalInput).on('submitted', function() {
// resetCommentInput has been called
if (!this.value) {
const sn = getSummernote(this);
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() {
// clear up unwanted tag info when user pasted in text
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
// would handle markdown and user mentions. We can simply have two
// 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));
}
return HTML.Raw(sanitizeXss(content));
}),
);
Template.viewer.events({
// Viewer sometimes have click-able wrapper around them (for instance to edit
// the corresponding text). Clicking a link shouldn't fire these actions, stop
// we stop these event at the viewer component level.
'click a'(event, templateInstance) {
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();
let prevent = true;
const userId = event.currentTarget.dataset.userid;
if (userId) {
Popup.open('member').call({ userId }, event, templateInstance);
} else {
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');
}
}
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();
}
},
});

View file

@ -232,6 +232,7 @@ kbd
background: darken(white, 2%)
border-radius: 3px
border: 1px solid darken(white, 10%)
color: unset
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15)
.clear

View file

@ -107,8 +107,8 @@ template(name="editUserPopup")
label
| {{_ 'password'}}
input.js-profile-password(type="password")
//div.buttonsContainer
// input.primary.wide(type="submit" value="{{_ 'save'}}")
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
// div
// input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")

View file

@ -22,6 +22,11 @@ template(name='homeSidebar')
+membersWidget
hr
+labelsWidget
ul#cards.label-text-hidden
a.flex.js-toggle-minicard-label-text
span {{_ 'hide-minicard-label-text'}}
b &nbsp;
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
hr
unless currentUser.isNoComments
h3

View file

@ -101,6 +101,9 @@ BlazeComponent.extendComponent({
'click .js-hide-sidebar': this.hide,
'click .js-toggle-sidebar': this.toggle,
'click .js-back-home': this.setView,
'click .js-toggle-minicard-label-text'() {
Meteor.call('toggleMinicardLabelText');
},
'click .js-shortcuts'() {
FlowRouter.go('shortcuts');
},
@ -111,6 +114,12 @@ BlazeComponent.extendComponent({
Blaze.registerHelper('Sidebar', () => Sidebar);
Template.homeSidebar.helpers({
hiddenMinicardLabelText() {
return Meteor.user().hasHiddenMinicardLabelText();
},
});
EscapeActions.register(
'sidebarView',
() => {

View file

@ -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) {
return string.charAt(0).toUpperCase() + string.slice(1);
},

View file

@ -232,6 +232,10 @@ services:
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60
#- 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 ====
# https://github.com/wekan/wekan/pull/2560
- RICHER_CARD_COMMENT_EDITOR=true

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -726,5 +726,6 @@
"act-duenow": "was reminding the current due (__timeValue__) of __card__ is now",
"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.",
"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"
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,27 +1,178 @@
Attachments = new FS.Collection('attachments', {
stores: [
const localFSStore = process.env.ATTACHMENTS_STORE_PATH;
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
// the general board view
new FS.Store.GridFS('attachments', {
// If the uploaded document is not an image we need to enforce browser
// 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
// appropriate `application/octet-stream` MIME header which can lead to user
// data leaks. I imagine other formats (like PDF) can also be attack vectors.
// See https://github.com/wekan/wekan/issues/99
// XXX Should we use `beforeWrite` option of CollectionFS instead of
// collection-hooks?
// We should use `beforeWrite`.
beforeWrite: fileObj => {
if (!fileObj.isImage()) {
return {
type: 'application/octet-stream',
};
}
return {};
},
}),
],
// If the uploaded document is not an image we need to enforce browser
// 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
// appropriate `application/octet-stream` MIME header which can lead to user
// data leaks. I imagine other formats (like PDF) can also be attack vectors.
// See https://github.com/wekan/wekan/issues/99
// XXX Should we use `beforeWrite` option of CollectionFS instead of
// collection-hooks?
// We should use `beforeWrite`.
...defaultStoreOptions,
});
}
Attachments = new FS.Collection('attachments', {
stores: [store],
});
if (Meteor.isServer) {

View file

@ -109,7 +109,14 @@ Users.attachSchema(
},
'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,
optional: true,
@ -253,7 +260,7 @@ Users.attachSchema(
Users.allow({
update(userId) {
const user = Users.findOne(userId);
return user && Meteor.user().isAdmin;
return user; // && Meteor.user().isAdmin; // GitHub issue #2590
},
remove(userId, doc) {
const adminsNumber = Users.find({ isAdmin: true }).count();
@ -359,6 +366,11 @@ Users.helpers({
return profile.hiddenSystemMessages || false;
},
hasHiddenMinicardLabelText() {
const profile = this.profile || {};
return profile.hiddenMinicardLabelText || false;
},
getEmailBuffer() {
const { emailBuffer = [] } = this.profile || {};
return emailBuffer;
@ -462,6 +474,14 @@ Users.mutations({
};
},
toggleLabelText(value = false) {
return {
$set: {
'profile.hiddenMinicardLabelText': !value,
},
};
},
addNotification(activityId) {
return {
$addToSet: {
@ -525,6 +545,10 @@ Meteor.methods({
const user = Meteor.user();
user.toggleSystem(user.hasHiddenSystemMessages());
},
toggleMinicardLabelText() {
const user = Meteor.user();
user.toggleLabelText(user.hasHiddenMinicardLabelText());
},
changeLimitToShowCardsCount(limit) {
check(limit, Number);
Meteor.user().setShowCardsCountAt(limit);
@ -946,8 +970,8 @@ if (Meteor.isServer) {
if (Meteor.isServer) {
// Middleware which checks that API is enabled.
JsonRoutes.Middleware.use(function(req, res, next) {
const api = req.url.search('api');
if ((api === 1 && process.env.WITH_API === 'true') || api === -1) {
const api = req.url.startsWith('/api');
if ((api === true && process.env.WITH_API === 'true') || api === false) {
return next();
} else {
res.writeHead(301, { Location: '/' });

4973
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "wekan",
"version": "v3.08.0",
"version": "v3.15.0",
"description": "Open-Source kanban",
"private": true,
"scripts": {
@ -55,12 +55,15 @@
"dependencies": {
"@babel/runtime": "^7.5.4",
"ajv": "^5.0.0",
"babel-runtime": "^6.26.0",
"bcrypt": "^3.0.2",
"bson": "^4.0.0",
"bunyan": "^1.8.12",
"es6-promise": "^4.2.4",
"gridfs-stream": "^0.5.3",
"ldapjs": "^1.0.2",
"meteor-node-stubs": "^0.4.1",
"mongodb": "^2.2.19",
"os": "^0.1.1",
"page": "^1.8.6",
"qs": "^6.5.2",

View file

@ -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">
<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>
@ -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="dark-box"></div>
<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>
<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>

View file

@ -1,7 +1,7 @@
swagger: '2.0'
info:
title: Wekan REST API
version: v3.08
version: v3.11
description: |
The REST API allows you to control and extend Wekan with ease.

View file

@ -1,6 +1,6 @@
cd ~/repos/wekan
./releases/rebuild-release.sh
./releases/delete-phantomjs.sh
#./releases/delete-phantomjs.sh
cd ~/repos/wekan/.build
zip -r wekan-$1.zip bundle
scp wekan-$1.zip x2:/var/snap/wekan/common/releases.wekan.team/

View file

@ -1,12 +1,12 @@
# Usage: ./release.sh 1.36
# Delete old stuff
cd ~/repos/wekan
./releases/release-cleanup.sh
#cd ~/repos/wekan
#./releases/release-cleanup.sh
# Build Source
cd ~/repos/wekan
./releases/rebuild-release.sh
#cd ~/repos/wekan
#./releases/rebuild-release.sh
# Build Sandstorm
cd ~/repos/wekan
@ -16,6 +16,6 @@ scp wekan-$1.spk x2:/var/snap/wekan/common/releases.wekan.team/
mv wekan-$1.spk ..
# Delete old stuff
cd ~/repos/wekan
./releases/release-cleanup.sh
#cd ~/repos/wekan
#./releases/release-cleanup.sh

View file

@ -1,7 +1,10 @@
# Usage: ./release.sh 1.36
# Build Bundle
~/repos/wekan/releases/release-bundle.sh $1
# Build Sandstorm
./release-sandstorm.sh $1
~/repos/wekan/release-sandstorm.sh $1
# Build Snap
./release-snap.sh $1
#./release-snap.sh $1

View file

@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
appTitle = (defaultText = "Wekan"),
# The name of the app as it is displayed to the user.
appVersion = 310,
appVersion = 317,
# 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.
minUpgradableAppVersion = 0,

View 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';
}
});

View file

@ -3,7 +3,7 @@
# All supported keys are defined here together with descriptions and default values
# 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
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"
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"
DEFAULT_MAX_IMAGE_PIXEL=""
KEY_MAX_IMAGE_PIXEL="max-image-pixel"

View file

@ -81,6 +81,12 @@ echo -e "\t$ snap set $SNAP_NAME image-compress-ratio='80'"
echo -e "Disabled:"
echo -e "\t$ snap set $SNAP_NAME image-compress-ratio=''"
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 "Big events pattern: Notify always due etc regardless of notification settings. Default: due, All: received|start|due|end, Disabled: NONE"
echo -e "Default:"

View file

@ -104,11 +104,11 @@ parts:
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
# Delete meteor 1.8.x dependencies and
# move Snap's working meteor 1.6.0.1 dependencies to be used at Wekan Snap
rm -rf .meteor
mv .meteor-1.6-snap/.meteor .
mv .meteor-1.6-snap/package.json .
mv .meteor-1.6-snap/package-lock.json .
mv .meteor-1.6-snap/rebuild-wekan.sh .
#rm -rf .meteor
#mv .meteor-1.6-snap/.meteor .
#mv .meteor-1.6-snap/package.json .
#mv .meteor-1.6-snap/package-lock.json .
#mv .meteor-1.6-snap/rebuild-wekan.sh .
rm -rf .meteor-1.6-snap
# Create the OpenAPI specification
rm -rf .build
@ -201,6 +201,7 @@ parts:
rm -rf package-lock.json .build
meteor add standard-minifier-js --allow-superuser
meteor npm install --allow-superuser
meteor npm install --allow-superuser --save babel-runtime
meteor build .build --directory --allow-superuser
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.
@ -214,15 +215,20 @@ parts:
# Change to directory .build/bundle/programs/server
cd .build/bundle/programs/server
npm install
npm install --allow-superuser --save babel-runtime
#meteor npm install --save bcrypt
# Change back to Wekan source directory
cd ../../../..
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
rm $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 $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/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/wekan
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 -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/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:
README: README.wekan
prime:

View file

@ -80,7 +80,7 @@ cd /home/wekan/app_build/bundle/programs/server/
sudo npm install
sudo chown -R wekan:wekan ./node_modules
cd /home/wekan/app_build/bundle
find . -name "*phantomjs*" | sudo xargs rm -rf
#cd /home/wekan/app_build/bundle
#find . -name "*phantomjs*" | sudo xargs rm -rf
sudo mv /home/wekan/app_build/bundle /build