UserMembershipControllerTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const sinon = require('sinon')
  14. const assertCalledWith = sinon.assert.calledWith
  15. const assertNotCalled = sinon.assert.notCalled
  16. const chai = require('chai')
  17. const should = chai.should()
  18. const { assert } = chai
  19. const { expect } = require('chai')
  20. const modulePath =
  21. '../../../../app/src/Features/UserMembership/UserMembershipController.js'
  22. const SandboxedModule = require('sandboxed-module')
  23. const MockRequest = require('../helpers/MockRequest')
  24. const MockResponse = require('../helpers/MockResponse')
  25. const EntityConfigs = require('../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs')
  26. const Errors = require('../../../../app/src/Features/Errors/Errors')
  27. describe('UserMembershipController', function() {
  28. beforeEach(function() {
  29. this.req = new MockRequest()
  30. this.req.params.id = 'mock-entity-id'
  31. this.user = { _id: 'mock-user-id' }
  32. this.newUser = { _id: 'mock-new-user-id', email: 'new-user-email@foo.bar' }
  33. this.subscription = {
  34. _id: 'mock-subscription-id',
  35. fetchV1Data: callback => callback(null, this.subscription)
  36. }
  37. this.institution = {
  38. _id: 'mock-institution-id',
  39. v1Id: 123,
  40. fetchV1Data: callback => {
  41. const institution = Object.assign({}, this.institution)
  42. institution.name = 'Test Institution Name'
  43. return callback(null, institution)
  44. }
  45. }
  46. this.users = [
  47. {
  48. _id: 'mock-member-id-1',
  49. email: 'mock-email-1@foo.com',
  50. last_logged_in_at: '2020-08-09T12:43:11.467Z'
  51. },
  52. {
  53. _id: 'mock-member-id-2',
  54. email: 'mock-email-2@foo.com',
  55. last_logged_in_at: '2020-05-20T10:41:11.407Z'
  56. }
  57. ]
  58. this.AuthenticationController = {
  59. getSessionUser: sinon.stub().returns(this.user),
  60. getLoggedInUserId: sinon.stub().returns(this.user._id)
  61. }
  62. this.UserMembershipHandler = {
  63. getEntity: sinon.stub().yields(null, this.subscription),
  64. createEntity: sinon.stub().yields(null, this.institution),
  65. getUsers: sinon.stub().yields(null, this.users),
  66. addUser: sinon.stub().yields(null, this.newUser),
  67. removeUser: sinon.stub().yields(null)
  68. }
  69. return (this.UserMembershipController = SandboxedModule.require(
  70. modulePath,
  71. {
  72. globals: {
  73. console: console
  74. },
  75. requires: {
  76. '../Authentication/AuthenticationController': this
  77. .AuthenticationController,
  78. './UserMembershipHandler': this.UserMembershipHandler,
  79. 'logger-sharelatex': {
  80. log() {},
  81. err() {}
  82. }
  83. }
  84. }
  85. ))
  86. })
  87. describe('index', function() {
  88. beforeEach(function() {
  89. this.req.entity = this.subscription
  90. return (this.req.entityConfig = EntityConfigs.group)
  91. })
  92. it('get users', function(done) {
  93. return this.UserMembershipController.index(this.req, {
  94. render: () => {
  95. sinon.assert.calledWithMatch(
  96. this.UserMembershipHandler.getUsers,
  97. this.subscription,
  98. { modelName: 'Subscription' }
  99. )
  100. return done()
  101. }
  102. })
  103. })
  104. it('render group view', function(done) {
  105. return this.UserMembershipController.index(this.req, {
  106. render: (viewPath, viewParams) => {
  107. expect(viewPath).to.equal('user_membership/index')
  108. expect(viewParams.users).to.deep.equal(this.users)
  109. expect(viewParams.groupSize).to.equal(this.subscription.membersLimit)
  110. expect(viewParams.translations.title).to.equal('group_account')
  111. expect(viewParams.paths.addMember).to.equal(
  112. `/manage/groups/${this.subscription._id}/invites`
  113. )
  114. return done()
  115. }
  116. })
  117. })
  118. it('render group managers view', function(done) {
  119. this.req.entityConfig = EntityConfigs.groupManagers
  120. return this.UserMembershipController.index(this.req, {
  121. render: (viewPath, viewParams) => {
  122. expect(viewPath).to.equal('user_membership/index')
  123. expect(viewParams.groupSize).to.equal(undefined)
  124. expect(viewParams.translations.title).to.equal('group_account')
  125. expect(viewParams.translations.subtitle).to.equal(
  126. 'managers_management'
  127. )
  128. expect(viewParams.paths.exportMembers).to.be.undefined
  129. return done()
  130. }
  131. })
  132. })
  133. it('render institution view', function(done) {
  134. this.req.entity = this.institution
  135. this.req.entityConfig = EntityConfigs.institution
  136. return this.UserMembershipController.index(this.req, {
  137. render: (viewPath, viewParams) => {
  138. expect(viewPath).to.equal('user_membership/index')
  139. expect(viewParams.name).to.equal('Test Institution Name')
  140. expect(viewParams.groupSize).to.equal(undefined)
  141. expect(viewParams.translations.title).to.equal('institution_account')
  142. expect(viewParams.paths.exportMembers).to.be.undefined
  143. return done()
  144. }
  145. })
  146. })
  147. })
  148. describe('add', function() {
  149. beforeEach(function() {
  150. this.req.body.email = this.newUser.email
  151. this.req.entity = this.subscription
  152. return (this.req.entityConfig = EntityConfigs.groupManagers)
  153. })
  154. it('add user', function(done) {
  155. return this.UserMembershipController.add(this.req, {
  156. json: () => {
  157. sinon.assert.calledWithMatch(
  158. this.UserMembershipHandler.addUser,
  159. this.subscription,
  160. { modelName: 'Subscription' },
  161. this.newUser.email
  162. )
  163. return done()
  164. }
  165. })
  166. })
  167. it('return user object', function(done) {
  168. return this.UserMembershipController.add(this.req, {
  169. json: payload => {
  170. payload.user.should.equal(this.newUser)
  171. return done()
  172. }
  173. })
  174. })
  175. it('handle readOnly entity', function(done) {
  176. this.req.entityConfig = EntityConfigs.group
  177. return this.UserMembershipController.add(this.req, null, error => {
  178. expect(error).to.exist
  179. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  180. return done()
  181. })
  182. })
  183. it('handle user already added', function(done) {
  184. this.UserMembershipHandler.addUser.yields({ alreadyAdded: true })
  185. return this.UserMembershipController.add(this.req, {
  186. status: () => ({
  187. json: payload => {
  188. expect(payload.error.code).to.equal('user_already_added')
  189. return done()
  190. }
  191. })
  192. })
  193. })
  194. it('handle user not found', function(done) {
  195. this.UserMembershipHandler.addUser.yields({ userNotFound: true })
  196. return this.UserMembershipController.add(this.req, {
  197. status: () => ({
  198. json: payload => {
  199. expect(payload.error.code).to.equal('user_not_found')
  200. return done()
  201. }
  202. })
  203. })
  204. })
  205. it('handle invalid email', function(done) {
  206. this.req.body.email = 'not_valid_email'
  207. return this.UserMembershipController.add(this.req, {
  208. status: () => ({
  209. json: payload => {
  210. expect(payload.error.code).to.equal('invalid_email')
  211. return done()
  212. }
  213. })
  214. })
  215. })
  216. })
  217. describe('remove', function() {
  218. beforeEach(function() {
  219. this.req.params.userId = this.newUser._id
  220. this.req.entity = this.subscription
  221. return (this.req.entityConfig = EntityConfigs.groupManagers)
  222. })
  223. it('remove user', function(done) {
  224. return this.UserMembershipController.remove(this.req, {
  225. sendStatus: () => {
  226. sinon.assert.calledWithMatch(
  227. this.UserMembershipHandler.removeUser,
  228. this.subscription,
  229. { modelName: 'Subscription' },
  230. this.newUser._id
  231. )
  232. return done()
  233. }
  234. })
  235. })
  236. it('handle readOnly entity', function(done) {
  237. this.req.entityConfig = EntityConfigs.group
  238. return this.UserMembershipController.remove(this.req, null, error => {
  239. expect(error).to.exist
  240. expect(error).to.be.an.instanceof(Errors.NotFoundError)
  241. return done()
  242. })
  243. })
  244. it('prevent self removal', function(done) {
  245. this.req.params.userId = this.user._id
  246. return this.UserMembershipController.remove(this.req, {
  247. status: () => ({
  248. json: payload => {
  249. expect(payload.error.code).to.equal('managers_cannot_remove_self')
  250. return done()
  251. }
  252. })
  253. })
  254. })
  255. it('prevent admin removal', function(done) {
  256. this.UserMembershipHandler.removeUser.yields({ isAdmin: true })
  257. return this.UserMembershipController.remove(this.req, {
  258. status: () => ({
  259. json: payload => {
  260. expect(payload.error.code).to.equal('managers_cannot_remove_admin')
  261. return done()
  262. }
  263. })
  264. })
  265. })
  266. })
  267. describe('exportCsv', function() {
  268. beforeEach(function() {
  269. this.req.entity = this.subscription
  270. this.req.entityConfig = EntityConfigs.groupManagers
  271. this.res = new MockResponse()
  272. this.res.contentType = sinon.stub()
  273. this.res.header = sinon.stub()
  274. this.res.send = sinon.stub()
  275. return this.UserMembershipController.exportCsv(this.req, this.res)
  276. })
  277. it('get users', function() {
  278. return sinon.assert.calledWithMatch(
  279. this.UserMembershipHandler.getUsers,
  280. this.subscription,
  281. { modelName: 'Subscription' }
  282. )
  283. })
  284. it('should set the correct content type on the request', function() {
  285. return assertCalledWith(this.res.contentType, 'text/csv')
  286. })
  287. it('should name the exported csv file', function() {
  288. return assertCalledWith(
  289. this.res.header,
  290. 'Content-Disposition',
  291. 'attachment; filename=Group.csv'
  292. )
  293. })
  294. it('should export the correct csv', function() {
  295. return assertCalledWith(
  296. this.res.send,
  297. '"email","last_logged_in_at"\n"mock-email-1@foo.com","2020-08-09T12:43:11.467Z"\n"mock-email-2@foo.com","2020-05-20T10:41:11.407Z"'
  298. )
  299. })
  300. })
  301. describe('new', function() {
  302. beforeEach(function() {
  303. this.req.params.name = 'publisher'
  304. return (this.req.params.id = 'abc')
  305. })
  306. it('renders view', function(done) {
  307. return this.UserMembershipController.new(this.req, {
  308. render: (viewPath, data) => {
  309. expect(data.entityName).to.eq('publisher')
  310. expect(data.entityId).to.eq('abc')
  311. return done()
  312. }
  313. })
  314. })
  315. })
  316. describe('create', function() {
  317. beforeEach(function() {
  318. this.req.params.name = 'institution'
  319. this.req.entityConfig = EntityConfigs.institution
  320. return (this.req.params.id = 123)
  321. })
  322. it('creates institution', function(done) {
  323. return this.UserMembershipController.create(this.req, {
  324. redirect: path => {
  325. expect(path).to.eq(EntityConfigs.institution.pathsFor(123).index)
  326. sinon.assert.calledWithMatch(
  327. this.UserMembershipHandler.createEntity,
  328. 123,
  329. { modelName: 'Institution' }
  330. )
  331. return done()
  332. }
  333. })
  334. })
  335. })
  336. })