mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
brought back the project_or_id style
Added functionality into project getter, its a big performance improvement for things like cloning projects. Clone a 500 element project, 1 mongo get or 500.
This commit is contained in:
parent
b5dd96aa71
commit
6a7395a287
6 changed files with 150 additions and 76 deletions
|
@ -36,7 +36,7 @@ module.exports =
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, (error, doc)->
|
ProjectEntityHandler.addDoc project._id, project.rootFolder[0]._id, "main.tex", docLines, (error, doc)->
|
||||||
if error?
|
if error?
|
||||||
logger.err err:error, "error adding doc"
|
logger.err err:error, "error adding doc when creating basic project"
|
||||||
return callback(error)
|
return callback(error)
|
||||||
ProjectEntityHandler.setRootDoc project._id, doc._id, (error) ->
|
ProjectEntityHandler.setRootDoc project._id, doc._id, (error) ->
|
||||||
callback(error, project)
|
callback(error, project)
|
||||||
|
|
|
@ -5,7 +5,6 @@ projectOptionsHandler = require('./ProjectOptionsHandler')
|
||||||
DocumentUpdaterHandler = require("../DocumentUpdater/DocumentUpdaterHandler")
|
DocumentUpdaterHandler = require("../DocumentUpdater/DocumentUpdaterHandler")
|
||||||
DocstoreManager = require "../Docstore/DocstoreManager"
|
DocstoreManager = require "../Docstore/DocstoreManager"
|
||||||
ProjectGetter = require("./ProjectGetter")
|
ProjectGetter = require("./ProjectGetter")
|
||||||
Project = require("../../models/Project").Project
|
|
||||||
_ = require('underscore')
|
_ = require('underscore')
|
||||||
async = require('async')
|
async = require('async')
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ module.exports =
|
||||||
duplicate: (owner, originalProjectId, newProjectName, callback)->
|
duplicate: (owner, originalProjectId, newProjectName, callback)->
|
||||||
DocumentUpdaterHandler.flushProjectToMongo originalProjectId, (err) ->
|
DocumentUpdaterHandler.flushProjectToMongo originalProjectId, (err) ->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
ProjectGetter.getProject originalProjectId, (err, originalProject) ->
|
ProjectGetter.getProject originalProjectId, {compiler:true, rootFolder:true, rootDoc_id:true}, (err, originalProject) ->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
projectCreationHandler.createBlankProject owner._id, newProjectName, (err, newProject)->
|
projectCreationHandler.createBlankProject owner._id, newProjectName, (err, newProject)->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
|
@ -36,7 +35,7 @@ module.exports =
|
||||||
return (callback)->
|
return (callback)->
|
||||||
content = docContents[doc._id.toString()]
|
content = docContents[doc._id.toString()]
|
||||||
return callback(new Error("doc_id not found: #{doc._id}")) if !content?
|
return callback(new Error("doc_id not found: #{doc._id}")) if !content?
|
||||||
projectEntityHandler.addDoc newProject._id, newParentFolder._id, doc.name, content.lines, (err, newDoc)->
|
projectEntityHandler.addDoc newProject, newParentFolder._id, doc.name, content.lines, (err, newDoc)->
|
||||||
if originalRootDoc? and newDoc.name == originalRootDoc.name
|
if originalRootDoc? and newDoc.name == originalRootDoc.name
|
||||||
setRootDoc newDoc._id
|
setRootDoc newDoc._id
|
||||||
callback()
|
callback()
|
||||||
|
@ -51,7 +50,7 @@ module.exports =
|
||||||
copyFolder = (folder, desFolder, callback)->
|
copyFolder = (folder, desFolder, callback)->
|
||||||
jobs = folder.folders.map (childFolder)->
|
jobs = folder.folders.map (childFolder)->
|
||||||
return (callback)->
|
return (callback)->
|
||||||
projectEntityHandler.addFolder newProject._id, desFolder._id, childFolder.name, (err, newFolder)->
|
projectEntityHandler.addFolder newProject, desFolder._id, childFolder.name, (err, newFolder)->
|
||||||
copyFolder childFolder, newFolder, callback
|
copyFolder childFolder, newFolder, callback
|
||||||
jobs.push (cb)->
|
jobs.push (cb)->
|
||||||
copyDocs folder, desFolder, cb
|
copyDocs folder, desFolder, cb
|
||||||
|
|
|
@ -109,8 +109,8 @@ module.exports = ProjectEntityHandler =
|
||||||
options = {}
|
options = {}
|
||||||
DocstoreManager.getDoc project_id, doc_id, options, callback
|
DocstoreManager.getDoc project_id, doc_id, options, callback
|
||||||
|
|
||||||
addDoc: (project_id, folder_id, docName, docLines, callback = (error, doc, folder_id) ->)=>
|
addDoc: (project_or_id, folder_id, docName, docLines, callback = (error, doc, folder_id) ->)=>
|
||||||
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project) ->
|
ProjectGetter.getProjectWithOnlyFolders project_or_id, (err, project) ->
|
||||||
logger.log project: project._id, folder_id: folder_id, doc_name: docName, "adding doc"
|
logger.log project: project._id, folder_id: folder_id, doc_name: docName, "adding doc"
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
confirmFolder project, folder_id, (folder_id)=>
|
confirmFolder project, folder_id, (folder_id)=>
|
||||||
|
@ -182,7 +182,7 @@ module.exports = ProjectEntityHandler =
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
copyFileFromExistingProject: (project_or_id, folder_id, originalProject_id, origonalFileRef, callback = (error, fileRef, folder_id) ->)->
|
copyFileFromExistingProject: (project_or_id, folder_id, originalProject_id, origonalFileRef, callback = (error, fileRef, folder_id) ->)->
|
||||||
Project.getProject project_or_id, "name", (err, project) ->
|
ProjectGetter.getProjectWithOnlyFolders project_or_id, {name:true}, (err, project) ->
|
||||||
logger.log project_id:project._id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "copying file in s3"
|
logger.log project_id:project._id, folder_id:folder_id, originalProject_id:originalProject_id, origonalFileRef:origonalFileRef, "copying file in s3"
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
confirmFolder project, folder_id, (folder_id)=>
|
confirmFolder project, folder_id, (folder_id)=>
|
||||||
|
@ -216,7 +216,7 @@ module.exports = ProjectEntityHandler =
|
||||||
if parentFolder?
|
if parentFolder?
|
||||||
parentFolder_id = parentFolder._id
|
parentFolder_id = parentFolder._id
|
||||||
builtUpPath = "#{builtUpPath}/#{folderName}"
|
builtUpPath = "#{builtUpPath}/#{folderName}"
|
||||||
projectLocator.findElementByPath project_id, builtUpPath, (err, foundFolder)=>
|
projectLocator.findElementByPath project, builtUpPath, (err, foundFolder)=>
|
||||||
if !foundFolder?
|
if !foundFolder?
|
||||||
logger.log path:path, project_id:project._id, folderName:folderName, "making folder from mkdirp"
|
logger.log path:path, project_id:project._id, folderName:folderName, "making folder from mkdirp"
|
||||||
@addFolder project_id, parentFolder_id, folderName, (err, newFolder, parentFolder_id)->
|
@addFolder project_id, parentFolder_id, folderName, (err, newFolder, parentFolder_id)->
|
||||||
|
@ -235,9 +235,9 @@ module.exports = ProjectEntityHandler =
|
||||||
!folder.filterOut
|
!folder.filterOut
|
||||||
callback(null, folders, lastFolder)
|
callback(null, folders, lastFolder)
|
||||||
|
|
||||||
addFolder: (project_id, parentFolder_id, folderName, callback) ->
|
addFolder: (project_or_id, parentFolder_id, folderName, callback) ->
|
||||||
folder = new Folder name: folderName
|
folder = new Folder name: folderName
|
||||||
ProjectGetter.getProjectWithOnlyFolders project_id, (err, project)=>
|
ProjectGetter.getProjectWithOnlyFolders project_or_id, (err, project)=>
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
confirmFolder project, parentFolder_id, (parentFolder_id)=>
|
confirmFolder project, parentFolder_id, (parentFolder_id)=>
|
||||||
logger.log project: project_id, parentFolder_id:parentFolder_id, folderName:folderName, "new folder added"
|
logger.log project: project_id, parentFolder_id:parentFolder_id, folderName:folderName, "new folder added"
|
||||||
|
@ -318,7 +318,6 @@ module.exports = ProjectEntityHandler =
|
||||||
logger.err err: "No entityType set", project_id: project_id, entity_id: entity_id
|
logger.err err: "No entityType set", project_id: project_id, entity_id: entity_id
|
||||||
return callback("No entityType set")
|
return callback("No entityType set")
|
||||||
entityType = entityType.toLowerCase()
|
entityType = entityType.toLowerCase()
|
||||||
console.log "getting project"
|
|
||||||
ProjectGetter.getProject project_id, {name:true, rootFolder:true}, (err, project)=>
|
ProjectGetter.getProject project_id, {name:true, rootFolder:true}, (err, project)=>
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
projectLocator.findElement {project: project, element_id: entity_id, type: entityType}, (error, entity, path)=>
|
projectLocator.findElement {project: project, element_id: entity_id, type: entityType}, (error, entity, path)=>
|
||||||
|
|
|
@ -2,31 +2,54 @@ mongojs = require("../../infrastructure/mongojs")
|
||||||
db = mongojs.db
|
db = mongojs.db
|
||||||
ObjectId = mongojs.ObjectId
|
ObjectId = mongojs.ObjectId
|
||||||
async = require "async"
|
async = require "async"
|
||||||
|
Errors = require("../../errors")
|
||||||
|
|
||||||
module.exports = ProjectGetter =
|
module.exports = ProjectGetter =
|
||||||
EXCLUDE_DEPTH: 8
|
EXCLUDE_DEPTH: 8
|
||||||
|
|
||||||
getProjectWithoutDocLines: (project_id, callback=(error, project) ->) ->
|
|
||||||
excludes = {}
|
|
||||||
for i in [1..@EXCLUDE_DEPTH]
|
|
||||||
excludes["rootFolder#{Array(i).join(".folder")}.docs.lines"] = 0
|
|
||||||
db.projects.find _id: ObjectId(project_id.toString()), excludes, (error, projects = []) ->
|
|
||||||
callback error, projects[0]
|
|
||||||
|
|
||||||
getProjectWithOnlyFolders: (project_id, callback=(error, project) ->) ->
|
_returnProjectIfPassed: (project_or_id, callback, continueCallback)->
|
||||||
excludes = {}
|
if project_or_id._id?
|
||||||
for i in [1..@EXCLUDE_DEPTH]
|
callback null, project_or_id
|
||||||
excludes["rootFolder#{Array(i).join(".folder")}.docs"] = 0
|
else
|
||||||
excludes["rootFolder#{Array(i).join(".folder")}.fileRefs"] = 0
|
try
|
||||||
db.projects.find _id: ObjectId(project_id.toString()), excludes, (error, projects = []) ->
|
ObjectId(project_or_id.toString())
|
||||||
callback error, projects[0]
|
catch e
|
||||||
|
return continueCallback(new Errors.NotFoundError(e.message))
|
||||||
|
continueCallback()
|
||||||
|
|
||||||
|
getProjectWithoutDocLines: (project_or_id, callback=(error, project) ->) ->
|
||||||
|
ProjectGetter._returnProjectIfPassed project_or_id, callback, (err)->
|
||||||
|
return callback(err) if err?
|
||||||
|
project_id = project_or_id
|
||||||
|
excludes = {}
|
||||||
|
for i in [1..ProjectGetter.EXCLUDE_DEPTH]
|
||||||
|
excludes["rootFolder#{Array(i).join(".folder")}.docs.lines"] = 0
|
||||||
|
db.projects.find _id: ObjectId(project_id.toString()), excludes, (error, projects = []) ->
|
||||||
|
callback error, projects[0]
|
||||||
|
|
||||||
|
getProjectWithOnlyFolders: (project_or_id, callback=(error, project) ->) ->
|
||||||
|
ProjectGetter._returnProjectIfPassed project_or_id, callback, (err)->
|
||||||
|
return callback(err) if err?
|
||||||
|
project_id = project_or_id
|
||||||
|
excludes = {}
|
||||||
|
for i in [1..ProjectGetter.EXCLUDE_DEPTH]
|
||||||
|
excludes["rootFolder#{Array(i).join(".folder")}.docs"] = 0
|
||||||
|
excludes["rootFolder#{Array(i).join(".folder")}.fileRefs"] = 0
|
||||||
|
db.projects.find _id: ObjectId(project_id.toString()), excludes, (error, projects = []) ->
|
||||||
|
callback error, projects[0]
|
||||||
|
|
||||||
getProject: (query, projection, callback = (error, project) ->) ->
|
getProject: (query, projection, callback = (error, project) ->) ->
|
||||||
if typeof query == "string"
|
ProjectGetter._returnProjectIfPassed project_or_id, callback, (err)->
|
||||||
query = _id: ObjectId(query)
|
if typeof query == "string"
|
||||||
else if query instanceof ObjectId
|
query = _id: ObjectId(query)
|
||||||
query = _id: query
|
else if query instanceof ObjectId
|
||||||
db.projects.findOne query, projection, callback
|
query = _id: query
|
||||||
|
db.projects.find query, projection, (err, project)->
|
||||||
|
if err?
|
||||||
|
logger.err err:err, query:query, projection:projection, "error getting project"
|
||||||
|
return callback(err)
|
||||||
|
callback(null, project?[0])
|
||||||
|
|
||||||
populateProjectWithUsers: (project, callback=(error, project) ->) ->
|
populateProjectWithUsers: (project, callback=(error, project) ->) ->
|
||||||
# eventually this should be in a UserGetter.getUser module
|
# eventually this should be in a UserGetter.getUser module
|
||||||
|
|
|
@ -76,7 +76,7 @@ describe 'ProjectDuplicator', ->
|
||||||
findById: sinon.stub().callsArgWith(1, null, @project)
|
findById: sinon.stub().callsArgWith(1, null, @project)
|
||||||
|
|
||||||
@ProjectGetter =
|
@ProjectGetter =
|
||||||
getProject: sinon.stub().callsArgWith(1, null, @project)
|
getProject: sinon.stub().callsArgWith(2, null, @project)
|
||||||
|
|
||||||
@duplicator = SandboxedModule.require modulePath, requires:
|
@duplicator = SandboxedModule.require modulePath, requires:
|
||||||
'../../models/Project':{Project:@Project}
|
'../../models/Project':{Project:@Project}
|
||||||
|
|
|
@ -20,63 +20,116 @@ describe "ProjectGetter", ->
|
||||||
describe "getProjectWithoutDocLines", ->
|
describe "getProjectWithoutDocLines", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@project =
|
@project =
|
||||||
_id: @project_id = "0123456789abcd9876543210"
|
_id: @project_id = "56d46b0a1d3422b87c5ebcb1"
|
||||||
@db.projects.find = sinon.stub().callsArgWith(2, null, [@project])
|
@db.projects.find = sinon.stub().callsArgWith(2, null, [@project])
|
||||||
@ProjectGetter.getProjectWithoutDocLines @project_id, @callback
|
|
||||||
|
|
||||||
it "should call find with the project id", ->
|
describe "passing an id", ->
|
||||||
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
beforeEach ->
|
||||||
|
@ProjectGetter.getProjectWithoutDocLines @project_id, @callback
|
||||||
|
|
||||||
it "should exclude the doc lines", ->
|
it "should call find with the project id", ->
|
||||||
excludes =
|
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
||||||
"rootFolder.docs.lines": 0
|
|
||||||
"rootFolder.folder.docs.lines": 0
|
it "should exclude the doc lines", ->
|
||||||
"rootFolder.folder.folder.docs.lines": 0
|
excludes =
|
||||||
"rootFolder.folder.folder.folder.docs.lines": 0
|
"rootFolder.docs.lines": 0
|
||||||
"rootFolder.folder.folder.folder.folder.docs.lines": 0
|
"rootFolder.folder.docs.lines": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.docs.lines": 0
|
"rootFolder.folder.folder.docs.lines": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.docs.lines": 0
|
"rootFolder.folder.folder.folder.docs.lines": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.folder.docs.lines": 0
|
"rootFolder.folder.folder.folder.folder.docs.lines": 0
|
||||||
@db.projects.find.calledWith(sinon.match.any, excludes)
|
"rootFolder.folder.folder.folder.folder.folder.docs.lines": 0
|
||||||
.should.equal true
|
"rootFolder.folder.folder.folder.folder.folder.folder.docs.lines": 0
|
||||||
|
"rootFolder.folder.folder.folder.folder.folder.folder.folder.docs.lines": 0
|
||||||
|
@db.projects.find.calledWith(sinon.match.any, excludes)
|
||||||
|
.should.equal true
|
||||||
|
|
||||||
|
it "should call the callback with the project", ->
|
||||||
|
@callback.calledWith(null, @project).should.equal true
|
||||||
|
|
||||||
|
|
||||||
|
describe "passing a project", ->
|
||||||
|
beforeEach ->
|
||||||
|
@ProjectGetter.getProjectWithoutDocLines @project, @callback
|
||||||
|
|
||||||
|
it "should not call the db", ->
|
||||||
|
@db.projects.find.called.should.equal false
|
||||||
|
|
||||||
|
it "should call the callback with the project", ->
|
||||||
|
@callback.calledWith(null, @project).should.equal true
|
||||||
|
|
||||||
it "should call the callback with the project", ->
|
|
||||||
@callback.calledWith(null, @project).should.equal true
|
|
||||||
|
|
||||||
describe "getProjectWithOnlyFolders", ->
|
describe "getProjectWithOnlyFolders", ->
|
||||||
beforeEach ->
|
beforeEach ()->
|
||||||
@project =
|
@project =
|
||||||
_id: @project_id = "0123456789abcd9876543210"
|
_id: @project_id = "56d46b0a1d3422b87c5ebcb1"
|
||||||
@db.projects.find = sinon.stub().callsArgWith(2, null, [@project])
|
@db.projects.find = sinon.stub().callsArgWith(2, null, [@project])
|
||||||
@ProjectGetter.getProjectWithOnlyFolders @project_id, @callback
|
|
||||||
|
describe "passing an id", ->
|
||||||
|
beforeEach ->
|
||||||
|
@ProjectGetter.getProjectWithOnlyFolders @project_id, @callback
|
||||||
|
|
||||||
it "should call find with the project id", ->
|
it "should call find with the project id", ->
|
||||||
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
||||||
|
|
||||||
it "should exclude the docs and files lines", ->
|
it "should exclude the docs and files linesaaaa", ->
|
||||||
excludes =
|
excludes =
|
||||||
"rootFolder.docs": 0
|
"rootFolder.docs": 0
|
||||||
"rootFolder.fileRefs": 0
|
"rootFolder.fileRefs": 0
|
||||||
"rootFolder.folder.docs": 0
|
"rootFolder.folder.docs": 0
|
||||||
"rootFolder.folder.fileRefs": 0
|
"rootFolder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.docs": 0
|
"rootFolder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.folder.docs": 0
|
"rootFolder.folder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.docs": 0
|
"rootFolder.folder.folder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.folder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.docs": 0
|
"rootFolder.folder.folder.folder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.folder.folder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.docs": 0
|
"rootFolder.folder.folder.folder.folder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.folder.folder.folder.folder.fileRefs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.folder.docs": 0
|
"rootFolder.folder.folder.folder.folder.folder.folder.folder.docs": 0
|
||||||
"rootFolder.folder.folder.folder.folder.folder.folder.folder.fileRefs": 0
|
"rootFolder.folder.folder.folder.folder.folder.folder.folder.fileRefs": 0
|
||||||
@db.projects.find.calledWith(sinon.match.any, excludes)
|
@db.projects.find.calledWith(sinon.match.any, excludes).should.equal true
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should call the callback with the project", ->
|
it "should call the callback with the project", ->
|
||||||
@callback.calledWith(null, @project).should.equal true
|
@callback.calledWith(null, @project).should.equal true
|
||||||
|
|
||||||
|
describe "passing a project", ->
|
||||||
|
beforeEach ->
|
||||||
|
@ProjectGetter.getProjectWithoutDocLines @project, @callback
|
||||||
|
|
||||||
|
it "should not call the db", ->
|
||||||
|
@db.projects.find.called.should.equal false
|
||||||
|
|
||||||
|
it "should call the callback with the project", ->
|
||||||
|
@callback.calledWith(null, @project).should.equal true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe "getProject", ->
|
||||||
|
beforeEach ()->
|
||||||
|
@project =
|
||||||
|
_id: @project_id = "56d46b0a1d3422b87c5ebcb1"
|
||||||
|
@db.projects.find = sinon.stub().callsArgWith(2, null, [@project])
|
||||||
|
|
||||||
|
|
||||||
|
it "should call find with the project id when string id is passed", (done)->
|
||||||
|
@ProjectGetter.getProject @project_id, (err, project)=>
|
||||||
|
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
||||||
|
assert.deepEqual @project, project
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should call find with the project id when object id is passed", (done)->
|
||||||
|
@ProjectGetter.getProject ObjectId(@project_id), (err, project)=>
|
||||||
|
@db.projects.find.calledWith(_id: ObjectId(@project_id)).should.equal true
|
||||||
|
assert.deepEqual @project, project
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should not call db when project is passed", (done)->
|
||||||
|
@ProjectGetter.getProject ObjectId(@project_id), (err, project)=>
|
||||||
|
@db.projects.find.called.should.equal false
|
||||||
|
assert.deepEqual @project, project
|
||||||
|
done()
|
||||||
|
|
||||||
describe "populateProjectWithUsers", ->
|
describe "populateProjectWithUsers", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
|
Loading…
Reference in a new issue