wekan-0003: MOAD-0001 wekanCreator.js member dedup uses Array.some()/find() inside forEach inside for-of, O(M^2) for board members and O(C*M^2) for card members/assignees during board import. Fix: Set-based dedup O(1). 58.8x op-count reduction (board), 5.6x (cards). 4/4 PASS. rocketchat-0003: MOAD-0001 endDirectCall() calls call.users.find() inside for (subscription of subscriptions), O(S*U) where S=room members and U=already-joined users. Fix: build Set before loop for O(1) lookup. 100x speedup modeled at S=10000, J=100. 5/5 PASS. rocketchat-0004: MOAD-0004 CWE-312 oauth2-server/model.ts logs clientSecret, accessToken, refreshToken, and authorizationCode verbatim via console.log when debug=true. Fix: replace credential values with [REDACTED] sentinel. Wekan MOAD-0002/0003/0004/0005 CLEAN (Meteor 3.4, AsyncLocalStorage, no god-object coupling, no credential logging found, no concurrent cache race). Rocket.Chat MOAD-0002/0003/0005 CLEAN (Meteor 3.3.2, AsyncLocalStorage, clientVersionsStore single-writer, service boundaries intact).
98 lines
3.7 KiB
Diff
98 lines
3.7 KiB
Diff
--- a/models/wekanCreator.js
|
|
+++ b/models/wekanCreator.js
|
|
@@ -323,11 +323,13 @@ class WekanCreator {
|
|
// now add other members
|
|
if (boardToImport.members) {
|
|
- boardToImport.members.forEach(wekanMember => {
|
|
- // is it defined and do we already have it in our list?
|
|
- if (
|
|
- wekanMember.wekanId &&
|
|
- !boardToCreate.members.some(
|
|
- member => member.wekanId === wekanMember.wekanId,
|
|
- )
|
|
- )
|
|
- boardToCreate.members.push({
|
|
- ...wekanMember,
|
|
- userId: wekanMember.wekanId,
|
|
- });
|
|
- });
|
|
+ // Build a Set of already-present wekanIds so dedup is O(1) per member
|
|
+ // instead of O(M) per member (was O(M^2) overall).
|
|
+ const seenWekanIds = new Set(
|
|
+ boardToCreate.members.map(m => m.wekanId).filter(Boolean),
|
|
+ );
|
|
+ boardToImport.members.forEach(wekanMember => {
|
|
+ if (wekanMember.wekanId && !seenWekanIds.has(wekanMember.wekanId)) {
|
|
+ seenWekanIds.add(wekanMember.wekanId);
|
|
+ boardToCreate.members.push({
|
|
+ ...wekanMember,
|
|
+ userId: wekanMember.wekanId,
|
|
+ });
|
|
+ }
|
|
+ });
|
|
}
|
|
|
|
@@ -410,18 +412,22 @@ class WekanCreator {
|
|
// add members
|
|
if (card.members) {
|
|
- const wekanMembers = [];
|
|
- // we can't just map, as some members may not have been mapped
|
|
- card.members.forEach(sourceMemberId => {
|
|
- if (this.members[sourceMemberId]) {
|
|
- const wekanId = this.members[sourceMemberId];
|
|
- // we may map multiple Wekan members to the same wekan user
|
|
- // in which case we risk adding the same user multiple times
|
|
- if (!wekanMembers.find(wId => wId === wekanId)) {
|
|
- wekanMembers.push(wekanId);
|
|
- }
|
|
- }
|
|
- return true;
|
|
- });
|
|
+ // Use a Set for O(1) dedup instead of Array.find() O(M) per member.
|
|
+ const seenMemberIds = new Set();
|
|
+ const wekanMembers = [];
|
|
+ card.members.forEach(sourceMemberId => {
|
|
+ if (this.members[sourceMemberId]) {
|
|
+ const wekanId = this.members[sourceMemberId];
|
|
+ if (!seenMemberIds.has(wekanId)) {
|
|
+ seenMemberIds.add(wekanId);
|
|
+ wekanMembers.push(wekanId);
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ });
|
|
if (wekanMembers.length > 0) {
|
|
cardToCreate.members = wekanMembers;
|
|
}
|
|
@@ -429,18 +435,22 @@ class WekanCreator {
|
|
// add assignees
|
|
if (card.assignees) {
|
|
- const wekanAssignees = [];
|
|
- // we can't just map, as some members may not have been mapped
|
|
- card.assignees.forEach(sourceMemberId => {
|
|
- if (this.members[sourceMemberId]) {
|
|
- const wekanId = this.members[sourceMemberId];
|
|
- // we may map multiple Wekan members to the same wekan user
|
|
- // in which case we risk adding the same user multiple times
|
|
- if (!wekanAssignees.find(wId => wId === wekanId)) {
|
|
- wekanAssignees.push(wekanId);
|
|
- }
|
|
- }
|
|
- return true;
|
|
- });
|
|
+ // Same Set-based dedup for assignees.
|
|
+ const seenAssigneeIds = new Set();
|
|
+ const wekanAssignees = [];
|
|
+ card.assignees.forEach(sourceMemberId => {
|
|
+ if (this.members[sourceMemberId]) {
|
|
+ const wekanId = this.members[sourceMemberId];
|
|
+ if (!seenAssigneeIds.has(wekanId)) {
|
|
+ seenAssigneeIds.add(wekanId);
|
|
+ wekanAssignees.push(wekanId);
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ });
|
|
if (wekanAssignees.length > 0) {
|
|
cardToCreate.assignees = wekanAssignees;
|
|
}
|