mirror of
https://github.com/wekan/wekan.git
synced 2026-03-03 20:30:15 +01:00
Merge branch 'master' of https://github.com/wekan/wekan
This commit is contained in:
commit
241c3ed8ae
332 changed files with 18869 additions and 18221 deletions
9
server/accounts-common.js
Normal file
9
server/accounts-common.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Meteor.startup(() => {
|
||||
if (Meteor.isServer) {
|
||||
import { AccountsCommon } from 'meteor/accounts-base';
|
||||
|
||||
Accounts.config({
|
||||
loginExpirationInDays: process.env.ACCOUNTS_COMMON_LOGIN_EXPIRATION_IN_DAYS || 90,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import AccountSettings from '../models/accountSettings';
|
||||
import TableVisibilityModeSettings from '../models/tableVisibilityModeSettings';
|
||||
import Actions from '../models/actions';
|
||||
import Activities from '../models/activities';
|
||||
import Announcements from '../models/announcements';
|
||||
|
|
@ -645,6 +646,7 @@ Migrations.add('mutate-boardIds-in-customfields', () => {
|
|||
|
||||
const modifiedAtTables = [
|
||||
AccountSettings,
|
||||
TableVisibilityModeSettings,
|
||||
Actions,
|
||||
Activities,
|
||||
Announcements,
|
||||
|
|
@ -699,6 +701,7 @@ Migrations.add('add-missing-created-and-modified', () => {
|
|||
Migrations.add('fix-incorrect-dates', () => {
|
||||
const tables = [
|
||||
AccountSettings,
|
||||
TableVisibilityModeSettings,
|
||||
Actions,
|
||||
Activities,
|
||||
Announcements,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//var nodemailer = require('nodemailer');
|
||||
|
||||
// buffer each user's email text in a queue, then flush them in single email
|
||||
Meteor.startup(() => {
|
||||
Notifications.subscribe('email', (user, title, description, params) => {
|
||||
|
|
@ -38,6 +40,30 @@ Meteor.startup(() => {
|
|||
const html = texts.join('<br/>\n\n');
|
||||
user.clearEmailBuffer();
|
||||
try {
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
html,
|
||||
})
|
||||
} else {
|
||||
Email.send({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
html,
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
|
|
|
|||
|
|
@ -34,27 +34,32 @@ Meteor.publish('attachmentsList', function() {
|
|||
|
||||
Meteor.publish('orphanedAttachments', function() {
|
||||
let keys = [];
|
||||
Attachments.find({}, { fields: { copies: 1 } }).forEach(att => {
|
||||
keys.push(new ObjectID(att.copies.attachments.key));
|
||||
});
|
||||
keys.sort();
|
||||
keys = _.uniq(keys, true);
|
||||
|
||||
return AttachmentStorage.find(
|
||||
{ _id: { $nin: keys } },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
filename: 1,
|
||||
md5: 1,
|
||||
length: 1,
|
||||
contentType: 1,
|
||||
metadata: 1,
|
||||
if (Attachments.find({}, { fields: { copies: 1 } }) !== undefined) {
|
||||
Attachments.find({}, { fields: { copies: 1 } }).forEach(att => {
|
||||
keys.push(new ObjectID(att.copies.attachments.key));
|
||||
});
|
||||
keys.sort();
|
||||
keys = _.uniq(keys, true);
|
||||
|
||||
return AttachmentStorage.find(
|
||||
{ _id: { $nin: keys } },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
filename: 1,
|
||||
md5: 1,
|
||||
length: 1,
|
||||
contentType: 1,
|
||||
metadata: 1,
|
||||
},
|
||||
sort: {
|
||||
filename: 1,
|
||||
},
|
||||
limit: 250,
|
||||
},
|
||||
sort: {
|
||||
filename: 1,
|
||||
},
|
||||
limit: 250,
|
||||
},
|
||||
);
|
||||
);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ Meteor.publishRelations('board', function(boardId, isArchived) {
|
|||
this.cursor(Lists.find({ boardId, archived: isArchived }));
|
||||
this.cursor(Swimlanes.find({ boardId, archived: isArchived }));
|
||||
this.cursor(Integrations.find({ boardId }));
|
||||
this.cursor(CardCommentReactions.find({ boardId }));
|
||||
this.cursor(
|
||||
CustomFields.find(
|
||||
{ boardIds: { $in: [boardId] } },
|
||||
|
|
@ -161,6 +162,8 @@ Meteor.publishRelations('board', function(boardId, isArchived) {
|
|||
// Gather queries and send in bulk
|
||||
const cardComments = this.join(CardComments);
|
||||
cardComments.selector = _ids => ({ cardId: _ids });
|
||||
const cardCommentReactions = this.join(CardCommentReactions);
|
||||
cardCommentReactions.selector = _ids => ({ cardId: _ids });
|
||||
const attachments = this.join(Attachments);
|
||||
attachments.selector = _ids => ({ cardId: _ids });
|
||||
const checklists = this.join(Checklists);
|
||||
|
|
@ -194,12 +197,14 @@ Meteor.publishRelations('board', function(boardId, isArchived) {
|
|||
checklists.push(cardId);
|
||||
checklistItems.push(cardId);
|
||||
parentCards.push(cardId);
|
||||
cardCommentReactions.push(cardId)
|
||||
},
|
||||
);
|
||||
|
||||
// Send bulk queries for all found ids
|
||||
subCards.send();
|
||||
cardComments.send();
|
||||
cardCommentReactions.send();
|
||||
attachments.send();
|
||||
checklists.send();
|
||||
checklistItems.send();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,22 @@ const escapeForRegex = require('escape-string-regexp');
|
|||
|
||||
Meteor.publish('card', cardId => {
|
||||
check(cardId, String);
|
||||
return Cards.find({ _id: cardId });
|
||||
const ret = Cards.find({ _id: cardId });
|
||||
return ret;
|
||||
});
|
||||
|
||||
/** publish all data which is necessary to display card details as popup
|
||||
* @returns array of cursors
|
||||
*/
|
||||
Meteor.publishRelations('popupCardData', function(cardId) {
|
||||
check(cardId, String);
|
||||
this.cursor(
|
||||
Cards.find({_id: cardId}),
|
||||
function(cardId, card) {
|
||||
this.cursor(Boards.find({_id: card.boardId}));
|
||||
},
|
||||
);
|
||||
return this.ready()
|
||||
});
|
||||
|
||||
Meteor.publish('myCards', function(sessionId) {
|
||||
|
|
@ -113,7 +128,7 @@ function buildSelector(queryParams) {
|
|||
let selector = {};
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('queryParams:', queryParams);
|
||||
// console.log('queryParams:', queryParams);
|
||||
|
||||
if (queryParams.selector) {
|
||||
selector = queryParams.selector;
|
||||
|
|
@ -405,7 +420,7 @@ function buildSelector(queryParams) {
|
|||
|
||||
const items = ChecklistItems.find(
|
||||
{ title: regex },
|
||||
{ fields: { cardId: 1 } },
|
||||
{ fields: { cardId: 1, checklistId: 1 } },
|
||||
);
|
||||
const checklists = Checklists.find(
|
||||
{
|
||||
|
|
@ -424,23 +439,18 @@ function buildSelector(queryParams) {
|
|||
{ fields: { cardId: 1 } },
|
||||
);
|
||||
|
||||
selector.$and.push({
|
||||
$or: [
|
||||
let cardsSelector = [
|
||||
{ title: regex },
|
||||
{ description: regex },
|
||||
{ customFields: { $elemMatch: { value: regex } } },
|
||||
// {
|
||||
// _id: {
|
||||
// $in: CardComments.textSearch(userId, [queryParams.text]).map(
|
||||
// com => com.cardId,
|
||||
// ),
|
||||
// },
|
||||
// },
|
||||
{ _id: { $in: checklists.map(list => list.cardId) } },
|
||||
{ _id: { $in: attachments.map(attach => attach.cardId) } },
|
||||
{ _id: { $in: comments.map(com => com.cardId) } },
|
||||
],
|
||||
});
|
||||
];
|
||||
if (queryParams.text == "false" || queryParams.text == "true") {
|
||||
cardsSelector.push({ customFields: { $elemMatch: { value: queryParams.text == "true" ? true : false } } } );
|
||||
}
|
||||
selector.$and.push({ $or: cardsSelector });
|
||||
}
|
||||
|
||||
if (selector.$and.length === 0) {
|
||||
|
|
@ -449,9 +459,7 @@ function buildSelector(queryParams) {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('selector:', selector);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('selector.$and:', selector.$and);
|
||||
//console.log('cards selector:', JSON.stringify(selector, null, 2));
|
||||
|
||||
const query = new Query();
|
||||
query.selector = selector;
|
||||
|
|
@ -497,6 +505,7 @@ function buildProjection(query) {
|
|||
labelIds: 1,
|
||||
customFields: 1,
|
||||
userId: 1,
|
||||
description: 1,
|
||||
},
|
||||
sort: {
|
||||
boardId: 1,
|
||||
|
|
@ -612,7 +621,7 @@ function findCards(sessionId, query) {
|
|||
// console.log('selector:', query.selector);
|
||||
// console.log('selector.$and:', query.selector.$and);
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('projection:', projection);
|
||||
// console.log('projection:', query.projection);
|
||||
|
||||
const cards = Cards.find(query.selector, query.projection);
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
@ -715,6 +724,7 @@ function findCards(sessionId, query) {
|
|||
CustomFields.find({ _id: { $in: customFieldIds } }),
|
||||
Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
|
||||
Checklists.find({ cardId: { $in: cards.map(c => c._id) } }),
|
||||
ChecklistItems.find({ cardId: { $in: cards.map(c => c._id) } }),
|
||||
Attachments.find({ cardId: { $in: cards.map(c => c._id) } }),
|
||||
CardComments.find({ cardId: { $in: cards.map(c => c._id) } }),
|
||||
SessionData.find({ userId, sessionId }),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ Meteor.publish('setting', () => {
|
|||
displayAuthenticationMethod: 1,
|
||||
defaultAuthenticationMethod: 1,
|
||||
spinnerName: 1,
|
||||
oidcBtnText: 1,
|
||||
mailDomainName: 1,
|
||||
legalNotice: 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
|||
3
server/publications/tableVisibilityModeSettings.js
Normal file
3
server/publications/tableVisibilityModeSettings.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Meteor.publish('tableVisibilityModeSettings', function() {
|
||||
return TableVisibilityModeSettings.find();
|
||||
});
|
||||
|
|
@ -25,6 +25,7 @@ Meteor.publish('user-admin', function() {
|
|||
isAdmin: 1,
|
||||
teams: 1,
|
||||
orgs: 1,
|
||||
authenticationMethod: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//var nodemailer = require('nodemailer');
|
||||
|
||||
RulesHelper = {
|
||||
executeRules(activity) {
|
||||
const matchingRules = this.findMatchingRules(activity);
|
||||
|
|
@ -45,8 +47,12 @@ RulesHelper = {
|
|||
value = oldSwimlane.title;
|
||||
}
|
||||
}
|
||||
let matchesList = [value, '*'];
|
||||
if ((field === 'cardTitle') && (value !== undefined)) {
|
||||
matchesList = value.split(/\W/).concat(matchesList);
|
||||
}
|
||||
matchingMap[field] = {
|
||||
$in: [value, '*'],
|
||||
$in: matchesList,
|
||||
};
|
||||
});
|
||||
return matchingMap;
|
||||
|
|
@ -119,6 +125,30 @@ RulesHelper = {
|
|||
const text = action.emailMsg || '';
|
||||
const subject = action.emailSubject || '';
|
||||
try {
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
text,
|
||||
})
|
||||
} else {
|
||||
Email.send({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
text,
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { MongoInternals } from 'meteor/mongo';
|
||||
|
||||
// Sandstorm context is detected using the METEOR_SETTINGS environment variable
|
||||
// in the package definition.
|
||||
const isSandstorm =
|
||||
Meteor.settings && Meteor.settings.public && Meteor.settings.public.sandstorm;
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Meteor.methods({
|
||||
getStatistics() {
|
||||
|
|
@ -28,6 +33,35 @@ if (Meteor.isServer) {
|
|||
pid: process.pid,
|
||||
uptime: process.uptime(),
|
||||
};
|
||||
// Start: Show Nodejs heap stats at Standalone WeKan.
|
||||
//
|
||||
// Not shown at Sandstorm WeKan, because there's a bunch of machine performance data
|
||||
// Sandstorm doesn't expose to apps to prevent side channel attacks.
|
||||
if (!isSandstorm) {
|
||||
const v8 = require('v8'); // Import the v8 module
|
||||
statistics.nodeHeapStats = {
|
||||
totalHeapSize: v8.getHeapStatistics().total_heap_size,
|
||||
totalHeapSizeExecutable: v8.getHeapStatistics().total_heap_size_executable,
|
||||
totalPhysicalSize: v8.getHeapStatistics().total_physical_size,
|
||||
totalAvailableSize: v8.getHeapStatistics().total_available_size,
|
||||
usedHeapSize: v8.getHeapStatistics().used_heap_size,
|
||||
heapSizeLimit: v8.getHeapStatistics().heap_size_limit,
|
||||
mallocedMemory: v8.getHeapStatistics().malloced_memory,
|
||||
peakMallocedMemory: v8.getHeapStatistics().peak_malloced_memory,
|
||||
doesZapGarbage: v8.getHeapStatistics().does_zap_garbage,
|
||||
numberOfNativeContexts: v8.getHeapStatistics().number_of_native_contexts,
|
||||
numberOfDetachedContexts: v8.getHeapStatistics().number_of_detached_contexts,
|
||||
};
|
||||
let memoryUsage = process.memoryUsage();
|
||||
statistics.nodeMemoryUsage = {
|
||||
rss: memoryUsage.rss,
|
||||
heapTotal: memoryUsage.heapTotal,
|
||||
heapUsed: memoryUsage.heapUsed,
|
||||
external: memoryUsage.external,
|
||||
};
|
||||
}
|
||||
// End: Show Nodejs heap stats at Standalone WeKan.
|
||||
//
|
||||
// Remove beginning of Meteor release text METEOR@
|
||||
let meteorVersion = Meteor.release;
|
||||
meteorVersion = meteorVersion.replace('METEOR@', '');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue