summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLauri Ojansivu <x@xet7.org>2019-10-29 19:05:44 +0200
committerLauri Ojansivu <x@xet7.org>2019-10-29 19:05:44 +0200
commit7d6d3af54a2fc1fb68634725eb754b22f02fd430 (patch)
tree8703d32a5489dfce95e026bc535d6459c1743784 /models
parent13a2bd6380ced34a828b9469e48786ed21fcb380 (diff)
downloadwekan-7d6d3af54a2fc1fb68634725eb754b22f02fd430.tar.gz
wekan-7d6d3af54a2fc1fb68634725eb754b22f02fd430.tar.bz2
wekan-7d6d3af54a2fc1fb68634725eb754b22f02fd430.zip
Add Features: allowing lists to be sorted by modifiedAt when not in draggable mode.
Bug Fix #2093: the broken should be prior to file attachment feature introduced, and tested export board is working. Thanks to whowillcare ! ( xet7 merged this pull request manually from https://github.com/wekan/wekan/pull/2756 ) Closes #2093
Diffstat (limited to 'models')
-rw-r--r--models/boards.js17
-rw-r--r--models/cards.js28
-rw-r--r--models/export.js15
-rw-r--r--models/lists.js26
-rw-r--r--models/swimlanes.js15
-rw-r--r--models/users.js82
6 files changed, 174 insertions, 9 deletions
diff --git a/models/boards.js b/models/boards.js
index a9348478..85a7558c 100644
--- a/models/boards.js
+++ b/models/boards.js
@@ -409,6 +409,23 @@ Boards.helpers({
},
lists() {
+ const enabled = Meteor.user().hasSortBy();
+ return enabled ? this.newestLists() : this.draggableLists();
+ },
+
+ newestLists() {
+ // sorted lists from newest to the oldest, by its creation date or its cards' last modification date
+ const value = Meteor.user()._getListSortBy();
+ const sortKey = { starred: -1, [value[0]]: value[1] }; // [["starred",-1],value];
+ return Lists.find(
+ {
+ boardId: this._id,
+ archived: false,
+ },
+ { sort: sortKey },
+ );
+ },
+ draggableLists() {
return Lists.find({ boardId: this._id }, { sort: { sort: 1 } });
},
diff --git a/models/cards.js b/models/cards.js
index 635a4e72..27dda0ee 100644
--- a/models/cards.js
+++ b/models/cards.js
@@ -1695,6 +1695,25 @@ if (Meteor.isServer) {
const oldvalue = doc[action] || '';
const activityType = `a-${action}`;
const card = Cards.findOne(doc._id);
+ const list = card.list();
+ if (list && action === 'endAt') {
+ // change list modifiedAt
+ const modifiedAt = new Date(
+ new Date(value).getTime() - 365 * 24 * 3600 * 1e3,
+ ); // set it as 1 year before
+ const boardId = list.boardId;
+ Lists.direct.update(
+ {
+ _id: list._id,
+ },
+ {
+ $set: {
+ modifiedAt,
+ boardId,
+ },
+ },
+ );
+ }
const username = Users.findOne(userId).username;
const activity = {
userId,
@@ -1852,15 +1871,8 @@ if (Meteor.isServer) {
const check = Users.findOne({
_id: req.body.authorId,
});
+ const members = req.body.members || [req.body.authorId];
if (typeof check !== 'undefined') {
- let members = req.body.members || [];
- if (_.isString(members)) {
- if (members === '') {
- members = [];
- } else {
- members = [members];
- }
- }
const id = Cards.direct.insert({
title: req.body.title,
boardId: paramBoardId,
diff --git a/models/export.js b/models/export.js
index a69be970..056eefdc 100644
--- a/models/export.js
+++ b/models/export.js
@@ -50,12 +50,18 @@ if (Meteor.isServer) {
});
}
+// exporter maybe is broken since Gridfs introduced, add fs and path
+
export class Exporter {
constructor(boardId) {
this._boardId = boardId;
}
build() {
+ const fs = Npm.require('fs');
+ const os = Npm.require('os');
+ const path = Npm.require('path');
+
const byBoard = { boardId: this._boardId };
const byBoardNoLinked = {
boardId: this._boardId,
@@ -134,6 +140,11 @@ export class Exporter {
const getBase64Data = function(doc, callback) {
let buffer = new Buffer(0);
// callback has the form function (err, res) {}
+ const tmpFile = path.join(
+ os.tmpdir(),
+ `tmpexport${process.pid}${Math.random()}`,
+ );
+ const tmpWriteable = fs.createWriteStream(tmpFile);
const readStream = doc.createReadStream();
readStream.on('data', function(chunk) {
buffer = Buffer.concat([buffer, chunk]);
@@ -143,8 +154,12 @@ export class Exporter {
});
readStream.on('end', function() {
// done
+ fs.unlink(tmpFile, () => {
+ //ignored
+ });
callback(null, buffer.toString('base64'));
});
+ readStream.pipe(tmpWriteable);
};
const getBase64DataSync = Meteor.wrapAsync(getBase64Data);
result.attachments = Attachments.find(byBoard)
diff --git a/models/lists.js b/models/lists.js
index 9136c337..f06b15b1 100644
--- a/models/lists.js
+++ b/models/lists.js
@@ -11,6 +11,15 @@ Lists.attachSchema(
*/
type: String,
},
+ starred: {
+ /**
+ * if a list is stared
+ * then we put it on the top
+ */
+ type: Boolean,
+ optional: true,
+ defaultValue: false,
+ },
archived: {
/**
* is the list archived
@@ -81,10 +90,14 @@ Lists.attachSchema(
denyUpdate: false,
// eslint-disable-next-line consistent-return
autoValue() {
- if (this.isInsert || this.isUpsert || this.isUpdate) {
+ // this is redundant with updatedAt
+ /*if (this.isInsert || this.isUpsert || this.isUpdate) {
return new Date();
} else {
this.unset();
+ }*/
+ if (!this.isSet) {
+ return new Date();
}
},
},
@@ -252,6 +265,14 @@ Lists.helpers({
return this.type === 'template-list';
},
+ isStarred() {
+ return this.starred === true;
+ },
+
+ absoluteUrl() {
+ const card = Cards.findOne({ listId: this._id });
+ return card && card.absoluteUrl();
+ },
remove() {
Lists.remove({ _id: this._id });
},
@@ -261,6 +282,9 @@ Lists.mutations({
rename(title) {
return { $set: { title } };
},
+ star(enable = true) {
+ return { $set: { starred: !!enable } };
+ },
archive() {
if (this.isTemplateList()) {
diff --git a/models/swimlanes.js b/models/swimlanes.js
index 46e410da..831f1eff 100644
--- a/models/swimlanes.js
+++ b/models/swimlanes.js
@@ -174,6 +174,21 @@ Swimlanes.helpers({
},
lists() {
+ const enabled = Meteor.user().hasSortBy();
+ return enabled ? this.newestLists() : this.draggableLists();
+ },
+ newestLists() {
+ // sorted lists from newest to the oldest, by its creation date or its cards' last modification date
+ return Lists.find(
+ {
+ boardId: this.boardId,
+ swimlaneId: { $in: [this._id, ''] },
+ archived: false,
+ },
+ { sort: { modifiedAt: -1 } },
+ );
+ },
+ draggableLists() {
return Lists.find(
{
boardId: this.boardId,
diff --git a/models/users.js b/models/users.js
index 9147322c..83a224ba 100644
--- a/models/users.js
+++ b/models/users.js
@@ -4,6 +4,16 @@ const isSandstorm =
Meteor.settings && Meteor.settings.public && Meteor.settings.public.sandstorm;
Users = Meteor.users;
+const allowedSortValues = [
+ '-modifiedAt',
+ 'modifiedAt',
+ '-title',
+ 'title',
+ '-sort',
+ 'sort',
+];
+const defaultSortBy = allowedSortValues[0];
+
/**
* A User in wekan
*/
@@ -109,6 +119,13 @@ Users.attachSchema(
type: String,
optional: true,
},
+ 'profile.showDesktopDragHandles': {
+ /**
+ * does the user want to hide system messages?
+ */
+ type: Boolean,
+ optional: true,
+ },
'profile.hiddenSystemMessages': {
/**
* does the user want to hide system messages?
@@ -184,6 +201,15 @@ Users.attachSchema(
'board-view-cal',
],
},
+ 'profile.listSortBy': {
+ /**
+ * default sort list for user
+ */
+ type: String,
+ optional: true,
+ defaultValue: defaultSortBy,
+ allowedValues: allowedSortValues,
+ },
'profile.templatesBoardId': {
/**
* Reference to the templates board
@@ -358,6 +384,31 @@ Users.helpers({
return _.contains(invitedBoards, boardId);
},
+ _getListSortBy() {
+ const profile = this.profile || {};
+ const sortBy = profile.listSortBy || defaultSortBy;
+ const keyPattern = /^(-{0,1})(.*$)/;
+ const ret = [];
+ if (keyPattern.exec(sortBy)) {
+ ret[0] = RegExp.$2;
+ ret[1] = RegExp.$1 ? -1 : 1;
+ }
+ return ret;
+ },
+ hasSortBy() {
+ // if use doesn't have dragHandle, then we can let user to choose sort list by different order
+ return !this.hasShowDesktopDragHandles();
+ },
+ getListSortBy() {
+ return this._getListSortBy()[0];
+ },
+ getListSortTypes() {
+ return allowedSortValues;
+ },
+ getListSortByDirection() {
+ return this._getListSortBy()[1];
+ },
+
hasTag(tag) {
const { tags = [] } = this.profile || {};
return _.contains(tags, tag);
@@ -368,6 +419,11 @@ Users.helpers({
return _.contains(notifications, activityId);
},
+ hasShowDesktopDragHandles() {
+ const profile = this.profile || {};
+ return profile.showDesktopDragHandles || false;
+ },
+
hasHiddenSystemMessages() {
const profile = this.profile || {};
return profile.hiddenSystemMessages || false;
@@ -473,6 +529,21 @@ Users.mutations({
else this.addTag(tag);
},
+ setListSortBy(value) {
+ return {
+ $set: {
+ 'profile.listSortBy': value,
+ },
+ };
+ },
+ toggleDesktopHandles(value = false) {
+ return {
+ $set: {
+ 'profile.showDesktopDragHandles': !value,
+ },
+ };
+ },
+
toggleSystem(value = false) {
return {
$set: {
@@ -549,6 +620,14 @@ Meteor.methods({
Users.update(userId, { $set: { username } });
}
},
+ setListSortBy(value) {
+ check(value, String);
+ Meteor.user().setListSortBy(value);
+ },
+ toggleDesktopDragHandles() {
+ const user = Meteor.user();
+ user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
+ },
toggleSystemMessages() {
const user = Meteor.user();
user.toggleSystem(user.hasHiddenSystemMessages());
@@ -776,6 +855,9 @@ if (Meteor.isServer) {
if (Meteor.isServer) {
// Let mongoDB ensure username unicity
Meteor.startup(() => {
+ allowedSortValues.forEach(value => {
+ Lists._collection._ensureIndex(value);
+ });
Users._collection._ensureIndex({ modifiedAt: -1 });
Users._collection._ensureIndex(
{