浏览代码

Merge pull request #2720 from whowillcare/master

if username contains space, @ functions will fail at certain point
Lauri Ojansivu 5 年之前
父节点
当前提交
814e264521
共有 5 个文件被更改,包括 44 次插入27 次删除
  1. 13 5
      client/components/main/editor.js
  2. 1 0
      i18n/en.i18n.json
  3. 28 22
      models/activities.js
  4. 1 0
      models/cards.js
  5. 1 0
      models/users.js

+ 13 - 5
client/components/main/editor.js

@@ -94,7 +94,13 @@ Template.editor.onRendered(() => {
           currentBoard
           currentBoard
             .activeMembers()
             .activeMembers()
             .map(member => {
             .map(member => {
-              const username = Users.findOne(member.userId).username;
+              const user = Users.findOne(member.userId);
+              if (user._id === Meteor.userId()) {
+                return null;
+              }
+              const value = user.username;
+              const username =
+                value && value.match(/\s+/) ? `"${value}"` : value;
               return username.includes(term) ? username : null;
               return username.includes(term) ? username : null;
             })
             })
             .filter(Boolean),
             .filter(Boolean),
@@ -120,9 +126,10 @@ Template.editor.onRendered(() => {
       ? [
       ? [
           ['view', ['fullscreen']],
           ['view', ['fullscreen']],
           ['table', ['table']],
           ['table', ['table']],
-          ['font', ['bold', 'underline']],
-          //['fontsize', ['fontsize']],
+          ['font', ['bold']],
           ['color', ['color']],
           ['color', ['color']],
+          ['insert', ['video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
+          //['fontsize', ['fontsize']],
         ]
         ]
       : [
       : [
           ['style', ['style']],
           ['style', ['style']],
@@ -345,11 +352,12 @@ Blaze.Template.registerHelper(
       }
       }
       return member;
       return member;
     });
     });
-    const mentionRegex = /\B@([\w.]*)/gi;
+    const mentionRegex = /\B@(?:(?:"([\w.\s]*)")|([\w.]+))/gi; // including space in username
 
 
     let currentMention;
     let currentMention;
     while ((currentMention = mentionRegex.exec(content)) !== null) {
     while ((currentMention = mentionRegex.exec(content)) !== null) {
-      const [fullMention, username] = currentMention;
+      const [fullMention, quoteduser, simple] = currentMention;
+      const username = quoteduser || simple;
       const knowedUser = _.findWhere(knowedUsers, { username });
       const knowedUser = _.findWhere(knowedUsers, { username });
       if (!knowedUser) {
       if (!knowedUser) {
         continue;
         continue;

+ 1 - 0
i18n/en.i18n.json

@@ -731,6 +731,7 @@
   "almostdue": "current due time %s is approaching",
   "almostdue": "current due time %s is approaching",
   "pastdue": "current due time %s is past",
   "pastdue": "current due time %s is past",
   "duenow": "current due time %s is today",
   "duenow": "current due time %s is today",
+  "act-newDue": "__card__ has 1st due reminder [__board__]",
   "act-withDue": "__card__ due reminders [__board__]",
   "act-withDue": "__card__ due reminders [__board__]",
   "act-almostdue": "was reminding the current due (__timeValue__) of __card__ is approaching",
   "act-almostdue": "was reminding the current due (__timeValue__) of __card__ is approaching",
   "act-pastdue": "was reminding the current due (__timeValue__) of __card__ is past",
   "act-pastdue": "was reminding the current due (__timeValue__) of __card__ is past",

+ 28 - 22
models/activities.js

@@ -180,28 +180,34 @@ if (Meteor.isServer) {
       const comment = activity.comment();
       const comment = activity.comment();
       params.comment = comment.text;
       params.comment = comment.text;
       if (board) {
       if (board) {
-        const atUser = /(?:^|>|\b|\s)@(\S+?)(?:\s|$|<|\b)/g;
         const comment = params.comment;
         const comment = params.comment;
-        if (comment.match(atUser)) {
-          const commenter = params.user;
-          while (atUser.exec(comment)) {
-            const username = RegExp.$1;
-            if (commenter === username) {
-              // it's person at himself, ignore it?
-              continue;
-            }
-            const atUser =
-              Users.findOne(username) || Users.findOne({ username });
-            if (atUser && atUser._id) {
-              const uid = atUser._id;
-              params.atUsername = username;
-              params.atEmails = atUser.emails;
-              if (board.hasMember(uid)) {
-                title = 'act-atUserComment';
-                watchers = _.union(watchers, [uid]);
-              }
-            }
+        const knownUsers = board.members.map(member => {
+          const u = Users.findOne(member.userId);
+          if (u) {
+            member.username = u.username;
+            member.emails = u.emails;
           }
           }
+          return member;
+        });
+        const mentionRegex = /\B@(?:(?:"([\w.\s]*)")|([\w.]+))/gi; // including space in username
+        let currentMention;
+        while ((currentMention = mentionRegex.exec(comment)) !== null) {
+          /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]*/
+          const [ignored, quoteduser, simple] = currentMention;
+          const username = quoteduser || simple;
+          if (username === params.user) {
+            // ignore commenter mention himself?
+            continue;
+          }
+          const atUser = _.findWhere(knownUsers, { username });
+          if (!atUser) {
+            continue;
+          }
+          const uid = atUser.userId;
+          params.atUsername = username;
+          params.atEmails = atUser.emails;
+          title = 'act-atUserComment';
+          watchers = _.union(watchers, [uid]);
         }
         }
       }
       }
       params.commentId = comment._id;
       params.commentId = comment._id;
@@ -236,8 +242,8 @@ if (Meteor.isServer) {
       (!activity.timeKey || activity.timeKey === 'dueAt') &&
       (!activity.timeKey || activity.timeKey === 'dueAt') &&
       activity.timeValue
       activity.timeValue
     ) {
     ) {
-      // due time reminder
-      title = 'act-withDue';
+      // due time reminder, if it doesn't have old value, it's a brand new set, need some differentiation
+      title = activity.timeOldValue ? 'act-withDue' : 'act-newDue';
     }
     }
     ['timeValue', 'timeOldValue'].forEach(key => {
     ['timeValue', 'timeOldValue'].forEach(key => {
       // copy time related keys & values to params
       // copy time related keys & values to params

+ 1 - 0
models/cards.js

@@ -1558,6 +1558,7 @@ function cardRemover(userId, doc) {
 const findDueCards = days => {
 const findDueCards = days => {
   const seekDue = ($from, $to, activityType) => {
   const seekDue = ($from, $to, activityType) => {
     Cards.find({
     Cards.find({
+      archived: false,
       dueAt: { $gte: $from, $lt: $to },
       dueAt: { $gte: $from, $lt: $to },
     }).forEach(card => {
     }).forEach(card => {
       const username = Users.findOne(card.userId).username;
       const username = Users.findOne(card.userId).username;

+ 1 - 0
models/users.js

@@ -561,6 +561,7 @@ Users.mutations({
 Meteor.methods({
 Meteor.methods({
   setUsername(username, userId) {
   setUsername(username, userId) {
     check(username, String);
     check(username, String);
+    check(userId, String);
     const nUsersWithUsername = Users.find({ username }).count();
     const nUsersWithUsername = Users.find({ username }).count();
     if (nUsersWithUsername > 0) {
     if (nUsersWithUsername > 0) {
       throw new Meteor.Error('username-already-taken');
       throw new Meteor.Error('username-already-taken');