Просмотр исходного кода

Merge pull request #10667 from overleaf/ii-dashboard-duplicate-projects

[web] Remove duplicate projects when fetching all users projects

GitOrigin-RevId: b850cd6ea5a03f01ba82eaaba101afd21a5098cc
Tim Down 3 лет назад
Родитель
Сommit
079a0dcae4

+ 24 - 1
services/web/app/src/Features/Project/ProjectGetter.js

@@ -123,7 +123,30 @@ const ProjectGetter = {
               tokenReadAndWrite: projects.tokenReadAndWrite || [],
               tokenReadAndWrite: projects.tokenReadAndWrite || [],
               tokenReadOnly: projects.tokenReadOnly || [],
               tokenReadOnly: projects.tokenReadOnly || [],
             }
             }
-            callback(null, result)
+
+            // Remove duplicate projects. The order of result values is determined by the order they occur.
+            const tempAddedProjectsIds = new Set()
+            const filteredProjects = Object.entries(result).reduce(
+              (prev, current) => {
+                const [key, projects] = current
+
+                prev[key] = []
+
+                projects.forEach(project => {
+                  const projectId = project._id.toString()
+
+                  if (!tempAddedProjectsIds.has(projectId)) {
+                    prev[key].push(project)
+                    tempAddedProjectsIds.add(projectId)
+                  }
+                })
+
+                return prev
+              },
+              {}
+            )
+
+            callback(null, filteredProjects)
           }
           }
         )
         )
       }
       }

+ 73 - 27
services/web/test/unit/src/Project/ProjectGetterTests.js

@@ -288,30 +288,64 @@ describe('ProjectGetter', function () {
   describe('findAllUsersProjects', function () {
   describe('findAllUsersProjects', function () {
     beforeEach(function () {
     beforeEach(function () {
       this.fields = { mock: 'fields' }
       this.fields = { mock: 'fields' }
+      this.projectOwned = { _id: 'mock-owned-projects' }
+      this.projectRW = { _id: 'mock-rw-projects' }
+      this.projectRO = { _id: 'mock-ro-projects' }
+      this.projectTokenRW = { _id: 'mock-token-rw-projects' }
+      this.projectTokenRO = { _id: 'mock-token-ro-projects' }
       this.Project.find
       this.Project.find
         .withArgs({ owner_ref: this.userId }, this.fields)
         .withArgs({ owner_ref: this.userId }, this.fields)
-        .yields(null, ['mock-owned-projects'])
+        .yields(null, [this.projectOwned])
+    })
+
+    it('should call the callback with all the projects', function () {
       this.CollaboratorsGetter.getProjectsUserIsMemberOf.yields(null, {
       this.CollaboratorsGetter.getProjectsUserIsMemberOf.yields(null, {
-        readAndWrite: ['mock-rw-projects'],
-        readOnly: ['mock-ro-projects'],
-        tokenReadAndWrite: ['mock-token-rw-projects'],
-        tokenReadOnly: ['mock-token-ro-projects'],
+        readAndWrite: [this.projectRW],
+        readOnly: [this.projectRO],
+        tokenReadAndWrite: [this.projectTokenRW],
+        tokenReadOnly: [this.projectTokenRO],
       })
       })
       this.ProjectGetter.findAllUsersProjects(
       this.ProjectGetter.findAllUsersProjects(
         this.userId,
         this.userId,
         this.fields,
         this.fields,
         this.callback
         this.callback
       )
       )
+
+      this.callback
+        .calledWith(null, {
+          owned: [this.projectOwned],
+          readAndWrite: [this.projectRW],
+          readOnly: [this.projectRO],
+          tokenReadAndWrite: [this.projectTokenRW],
+          tokenReadOnly: [this.projectTokenRO],
+        })
+        .should.equal(true)
     })
     })
 
 
-    it('should call the callback with all the projects', function () {
+    it('should remove duplicate projects', function () {
+      this.CollaboratorsGetter.getProjectsUserIsMemberOf.yields(null, {
+        readAndWrite: [this.projectRW, this.projectOwned],
+        readOnly: [this.projectRO, this.projectRW],
+        tokenReadAndWrite: [this.projectTokenRW, this.projectRO],
+        tokenReadOnly: [
+          this.projectTokenRW,
+          this.projectTokenRO,
+          this.projectRO,
+        ],
+      })
+      this.ProjectGetter.findAllUsersProjects(
+        this.userId,
+        this.fields,
+        this.callback
+      )
+
       this.callback
       this.callback
         .calledWith(null, {
         .calledWith(null, {
-          owned: ['mock-owned-projects'],
-          readAndWrite: ['mock-rw-projects'],
-          readOnly: ['mock-ro-projects'],
-          tokenReadAndWrite: ['mock-token-rw-projects'],
-          tokenReadOnly: ['mock-token-ro-projects'],
+          owned: [this.projectOwned],
+          readAndWrite: [this.projectRW],
+          readOnly: [this.projectRO],
+          tokenReadAndWrite: [this.projectTokenRW],
+          tokenReadOnly: [this.projectTokenRO],
         })
         })
         .should.equal(true)
         .should.equal(true)
     })
     })
@@ -368,49 +402,61 @@ describe('ProjectGetter', function () {
 
 
   describe('findUsersProjectsByName', function () {
   describe('findUsersProjectsByName', function () {
     it('should perform a case-insensitive search', function (done) {
     it('should perform a case-insensitive search', function (done) {
+      this.project1 = { _id: 1, name: 'find me!' }
+      this.project2 = { _id: 2, name: 'not me!' }
+      this.project3 = { _id: 3, name: 'FIND ME!' }
+      this.project4 = { _id: 4, name: 'Find Me!' }
       this.Project.find
       this.Project.find
         .withArgs({ owner_ref: this.userId })
         .withArgs({ owner_ref: this.userId })
         .yields(null, [
         .yields(null, [
-          { name: 'find me!' },
-          { name: 'not me!' },
-          { name: 'FIND ME!' },
-          { name: 'Find Me!' },
+          this.project1,
+          this.project2,
+          this.project3,
+          this.project4,
         ])
         ])
       this.ProjectGetter.findUsersProjectsByName(
       this.ProjectGetter.findUsersProjectsByName(
         this.userId,
         this.userId,
-        'find me!',
+        this.project1.name,
         (err, projects) => {
         (err, projects) => {
           if (err != null) {
           if (err != null) {
             return done(err)
             return done(err)
           }
           }
-          projects
-            .map(project => project.name)
-            .should.have.members(['find me!', 'FIND ME!', 'Find Me!'])
+          const projectNames = projects.map(project => project.name)
+          expect(projectNames).to.have.members([
+            this.project1.name,
+            this.project3.name,
+            this.project4.name,
+          ])
           done()
           done()
         }
         }
       )
       )
     })
     })
 
 
     it('should search collaborations as well', function (done) {
     it('should search collaborations as well', function (done) {
+      this.project1 = { _id: 1, name: 'find me!' }
+      this.project2 = { _id: 2, name: 'FIND ME!' }
+      this.project3 = { _id: 3, name: 'Find Me!' }
+      this.project4 = { _id: 4, name: 'find ME!' }
+      this.project5 = { _id: 5, name: 'FIND me!' }
       this.Project.find
       this.Project.find
         .withArgs({ owner_ref: this.userId })
         .withArgs({ owner_ref: this.userId })
-        .yields(null, [{ name: 'find me!' }])
+        .yields(null, [this.project1])
       this.CollaboratorsGetter.getProjectsUserIsMemberOf.yields(null, {
       this.CollaboratorsGetter.getProjectsUserIsMemberOf.yields(null, {
-        readAndWrite: [{ name: 'FIND ME!' }],
-        readOnly: [{ name: 'Find Me!' }],
-        tokenReadAndWrite: [{ name: 'find ME!' }],
-        tokenReadOnly: [{ name: 'FIND me!' }],
+        readAndWrite: [this.project2],
+        readOnly: [this.project3],
+        tokenReadAndWrite: [this.project4],
+        tokenReadOnly: [this.project5],
       })
       })
       this.ProjectGetter.findUsersProjectsByName(
       this.ProjectGetter.findUsersProjectsByName(
         this.userId,
         this.userId,
-        'find me!',
+        this.project1.name,
         (err, projects) => {
         (err, projects) => {
           if (err != null) {
           if (err != null) {
             return done(err)
             return done(err)
           }
           }
           expect(projects.map(project => project.name)).to.have.members([
           expect(projects.map(project => project.name)).to.have.members([
-            'find me!',
-            'FIND ME!',
+            this.project1.name,
+            this.project2.name,
           ])
           ])
           done()
           done()
         }
         }