diff --git a/server/controllers/students/UpdateMailingList.js b/server/controllers/students/UpdateMailingList.js new file mode 100644 index 00000000..b7ff13ec --- /dev/null +++ b/server/controllers/students/UpdateMailingList.js @@ -0,0 +1,73 @@ +const Student = require('../../models/Student') +const Solicitation = require('../../models/Solicitation') +const { knex } = require('../../db') +const errors = require('../../../shared/errors') + +module.exports = async function updateMailingList(ctx) { + const { mailingList } = ctx.request.body + if ( + mailingList === undefined || + !['active', 'concluding', 'freshman'].includes(mailingList) + ) { + ctx.status = 400 + ctx.body = { code: errors.INVALID_FILTER, filter: 'mailingList' } + return + } + + let additions = 0 + let deletions = 0 + + await knex.transaction(async trx => { + const [modelsToAdd, modelsToRemove] = await Promise.all([ + Student.where('mailingListToAdd', mailingList).fetchAll({ + transacting: trx + }), + Student.where('mailingListToRemove', mailingList).fetchAll({ + transacting: trx + }) + ]) + + additions += modelsToAdd.length + deletions += modelsToRemove.length + + const promises = [] + + for (const model of modelsToRemove) { + const mailingList = + model.get('mailingList') === model.get('mailingListToRemove') + ? 'none' + : model.get('mailingList') + promises.push( + model.save( + { mailingList, mailingListToRemove: 'none' }, + { patch: true, transacting: trx } + ) + ) + } + + for (const model of modelsToAdd) { + promises.push( + model.save( + { mailingList, mailingListToAdd: 'none' }, + { patch: true, transacting: trx } + ) + ) + } + + if (['concluding', 'freshman'].includes(mailingList)) { + const query = { type: mailingList } + deletions += await Solicitation.where(query).count('*', { + transacting: trx + }) + promises.push(Solicitation.where(query).destroy({ transacting: trx })) + } + + return Promise.all(promises) + }) + + ctx.status = 200 + ctx.body = { + additions, + deletions + } +} diff --git a/server/controllers/students/index.js b/server/controllers/students/index.js index 931bd92b..9d515913 100644 --- a/server/controllers/students/index.js +++ b/server/controllers/students/index.js @@ -5,6 +5,7 @@ const Update = require('./Update') const ActiveMailList = require('./ActiveMailList') const UpdateAcademicHighlight = require('./UpdateAcademicHighlight') const EmailChanges = require('./EmailChanges') +const UpdateMailingList = require('./UpdateMailingList') module.exports = { List, @@ -13,5 +14,6 @@ module.exports = { Update, ActiveMailList, UpdateAcademicHighlight, - EmailChanges + EmailChanges, + UpdateMailingList } diff --git a/server/router.js b/server/router.js index 780d34a4..602661c7 100644 --- a/server/router.js +++ b/server/router.js @@ -46,6 +46,7 @@ api.put('/students/:id', bodyJson, students.Update) api.get('/students/:studentId/documents', documents.List) api.get('/students/:studentId/documents/:id', documents.Show) api.get('/students/:studentId/documents/:id/view', documents.View) +api.post('/students/update-mailing-list', bodyJson, students.UpdateMailingList) api.post('/students/:studentId/documents', bodyMultipart, documents.Upload) api.post('/students/from-csv', bodyMultipart, students.FromCsv) diff --git a/test/server/controllers/students.spec.js b/test/server/controllers/students.spec.js index b273bb8d..6d061ca2 100644 --- a/test/server/controllers/students.spec.js +++ b/test/server/controllers/students.spec.js @@ -11,6 +11,7 @@ const testUtils = require('../test-utils') const server = require('../../../server') const db = require('../../../server/db') const Student = require('../../../server/models/Student') +const Solicitation = require('../../../server/models/Solicitation') const errors = require('../../../shared/errors') const document = require('../../../server/models/Document') @@ -1188,56 +1189,179 @@ describe('/api/students', () => { done() }) -}) -test('GET /email-changes?mailingList=concluding', async done => { - const { token } = await testUtils.user('admin') - - const res = await chai - .request(server.listen()) - .get('/api/students/email-changes') - .query({ mailingList: 'concluding' }) - .set('Authorization', `Bearer ${token}`) - expect(res.status).toEqual(200) - expect(res.type).toEqual('application/json') - expect(res.body).toBeDefined() - expect(res.body.additions.length).toBeDefined() - expect(res.body.deletions.length).toBeDefined() - expect(res.body.deletions.length).toEqual(0) - - expect( - [ - 'JOSE FERREIRA SILVA', - 'JULIAN BARBOSA SANTOS', - 'Ana Goncalves Gomes', - 'Gabriela Dias Cunha', - 'Rodrigo Rodrigues Santos' - ].filter(name => !res.body.additions.find(student => student.name === name)) - ).toEqual([]) - - done() -}) + test('GET /email-changes?mailingList=concluding', async done => { + const { token } = await testUtils.user('admin') + + const res = await chai + .request(server.listen()) + .get('/api/students/email-changes') + .query({ mailingList: 'concluding' }) + .set('Authorization', `Bearer ${token}`) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions.length).toBeDefined() + expect(res.body.deletions.length).toBeDefined() + expect(res.body.deletions.length).toEqual(0) + + expect( + [ + 'JOSE FERREIRA SILVA', + 'JULIAN BARBOSA SANTOS', + 'Ana Goncalves Gomes', + 'Gabriela Dias Cunha', + 'Rodrigo Rodrigues Santos' + ].filter( + name => !res.body.additions.find(student => student.name === name) + ) + ).toEqual([]) + + done() + }) + + test('GET /email-changes?mailingList=freshman', async done => { + const { token } = await testUtils.user('admin') + + const res = await chai + .request(server.listen()) + .get('/api/students/email-changes') + .query({ mailingList: 'freshman' }) + .set('Authorization', `Bearer ${token}`) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions.length).toBeDefined() + expect(res.body.deletions.length).toBeDefined() + expect(res.body.deletions.length).toEqual(0) + + expect( + ['Victor Silva Carvalho', 'Marisa Correia Castro'].filter( + name => !res.body.additions.find(student => student.name === name) + ) + ).toEqual([]) + + done() + }) + + test('POST /update-mailing-list for actives then concluding', async done => { + const { token } = await testUtils.user('admin') + + { + const res = await chai + .request(server.listen()) + .post('/api/students/update-mailing-list') + .set('Authorization', `Bearer ${token}`) + .send({ mailingList: 'active' }) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions).toEqual(4) + expect(res.body.deletions).toEqual(3) + } + + expect(await Student.where({ mailingList: 'active' }).count()).toEqual(4) + expect(await Student.where({ mailingListToAdd: 'active' }).count()).toEqual( + 0 + ) + expect( + await Student.where({ mailingListToRemove: 'active' }).count() + ).toEqual(0) + + { + const res = await chai + .request(server.listen()) + .post('/api/students/update-mailing-list') + .set('Authorization', `Bearer ${token}`) + .send({ mailingList: 'concluding' }) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions).toEqual(2) + expect(res.body.deletions).toEqual(3) + } + + expect(await Student.where({ mailingList: 'concluding' }).count()).toEqual( + 2 + ) + expect( + await Student.where({ mailingListToAdd: 'concluding' }).count() + ).toEqual(0) + expect( + await Student.where({ mailingListToRemove: 'concluding' }).count() + ).toEqual(0) + expect(await Solicitation.where({ type: 'concluding' }).count()).toEqual(0) + + done() + }) + + test('POST /update-mailing-list for concluding then actives', async done => { + const { token } = await testUtils.user('admin') + + { + const res = await chai + .request(server.listen()) + .post('/api/students/update-mailing-list') + .set('Authorization', `Bearer ${token}`) + .send({ mailingList: 'concluding' }) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions).toEqual(2) + expect(res.body.deletions).toEqual(3) + } -test('GET /email-changes?mailingList=freshman', async done => { - const { token } = await testUtils.user('admin') - - const res = await chai - .request(server.listen()) - .get('/api/students/email-changes') - .query({ mailingList: 'freshman' }) - .set('Authorization', `Bearer ${token}`) - expect(res.status).toEqual(200) - expect(res.type).toEqual('application/json') - expect(res.body).toBeDefined() - expect(res.body.additions.length).toBeDefined() - expect(res.body.deletions.length).toBeDefined() - expect(res.body.deletions.length).toEqual(0) - - expect( - ['Victor Silva Carvalho', 'Marisa Correia Castro'].filter( - name => !res.body.additions.find(student => student.name === name) + expect(await Student.where({ mailingList: 'concluding' }).count()).toEqual( + 2 ) - ).toEqual([]) + expect( + await Student.where({ mailingListToAdd: 'concluding' }).count() + ).toEqual(0) + expect( + await Student.where({ mailingListToRemove: 'concluding' }).count() + ).toEqual(0) + expect(await Solicitation.where({ type: 'concluding' }).count()).toEqual(0) + + { + const res = await chai + .request(server.listen()) + .post('/api/students/update-mailing-list') + .set('Authorization', `Bearer ${token}`) + .send({ mailingList: 'active' }) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions).toEqual(4) + expect(res.body.deletions).toEqual(3) + } + + expect(await Student.where({ mailingList: 'active' }).count()).toEqual(4) + expect(await Student.where({ mailingListToAdd: 'active' }).count()).toEqual( + 0 + ) + expect( + await Student.where({ mailingListToRemove: 'active' }).count() + ).toEqual(0) + + done() + }) + + test('POST /update-mailing-list for freshman', async done => { + const { token } = await testUtils.user('admin') - done() + const res = await chai + .request(server.listen()) + .post('/api/students/update-mailing-list') + .set('Authorization', `Bearer ${token}`) + .send({ mailingList: 'freshman' }) + expect(res.status).toEqual(200) + expect(res.type).toEqual('application/json') + expect(res.body).toBeDefined() + expect(res.body.additions).toEqual(0) + expect(res.body.deletions).toEqual(2) + + expect(await Solicitation.where({ type: 'freshman' }).count()).toEqual(0) + + done() + }) })