Skip to content

Commit d71938a

Browse files
author
Alex G Rice
authored
New API route for "my teams" and "my moderated teams" (#152)
* Add new route and stub listMyTeams function. - New route /api/my/teams . - Verifies that the authenticate middleware is working. * Finish /api/my/teams route - Add unit test - Add `team.listModeratedBy` * Clean up test. * Finish listMyTeams() - rename public permission to public:authenticated, for clarity. - use can() middleware instead of authenticate middleware. - working unit test. * Improve unit test. - also edit .gitignore
1 parent 8167f09 commit d71938a

File tree

6 files changed

+84
-10
lines changed

6 files changed

+84
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ tmp
88
*.db
99
# ignore node_modules symlink
1010
node_modules.nosync
11+
.idea

app/lib/team.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ async function list (options) {
109109
return query
110110
}
111111

112+
/**
113+
* List all the teams which osm id is a moderator of.
114+
*
115+
* @param {*} osmId osm user id to filter by
116+
* @returns {Promise[Array]}
117+
*/
118+
async function listModeratedBy (osmId) {
119+
const conn = await db()
120+
const st = knexPostgis(conn)
121+
const query = conn('team')
122+
.select('*', st.asGeoJSON('location'))
123+
.whereIn('id', subQuery => subQuery.select('team_id').from('moderator').where('osm_id', osmId))
124+
return query
125+
}
126+
112127
/**
113128
* Create a team
114129
* Teams have to have moderators, so we give an osm id
@@ -315,6 +330,7 @@ async function isPublic (teamId) {
315330
module.exports = {
316331
get,
317332
list,
333+
listModeratedBy,
318334
create,
319335
update,
320336
destroy,

app/manage/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const {
1414
getTeam,
1515
joinTeam,
1616
listTeams,
17+
listMyTeams,
1718
removeMember,
1819
removeModerator,
1920
updateMembers,
@@ -60,6 +61,7 @@ function manageRouter (nextApp) {
6061
* List, Create, Read, Update, Delete operations on teams.
6162
*/
6263
router.get('/api/teams', listTeams)
64+
router.get('/api/my/teams', can('public:authenticated'), listMyTeams)
6365
router.post('/api/teams', can('team:create'), createTeam)
6466
router.get('/api/teams/:id', can('team:view'), getTeam)
6567
router.put('/api/teams/:id', can('team:update'), updateTeam)

app/manage/permissions/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const hydra = require('../../lib/hydra')
33
const { mergeAll } = require('ramda')
44

55
const metaPermissions = {
6-
'public': () => true
6+
'public:authenticated': () => true
77
}
88

99
const teamPermissions = {

app/manage/teams.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ async function listTeams (req, reply) {
2323
}
2424
}
2525

26+
async function listMyTeams (req, reply) {
27+
const { user_id: osmId } = reply.locals
28+
try {
29+
const memberOfTeams = await team.list({ osmId })
30+
const moderatorOfTeams = await team.listModeratedBy(osmId)
31+
const result = {
32+
osmId,
33+
member: memberOfTeams,
34+
moderator: moderatorOfTeams
35+
}
36+
reply.send(result)
37+
} catch (err) {
38+
return reply.boom.badRequest(err.message)
39+
}
40+
}
41+
2642
async function getTeam (req, reply) {
2743
const { id } = req.params
2844

@@ -50,7 +66,6 @@ async function getTeam (req, reply) {
5066
async function createTeam (req, reply) {
5167
const { body } = req
5268
const { user_id } = reply.locals
53-
5469
if (body.editing_policy && !isUrl.test(body.editing_policy)) {
5570
return reply.boom.badRequest('editing_policy must be a valid url')
5671
}
@@ -231,6 +246,7 @@ module.exports = {
231246
getTeam,
232247
joinTeam,
233248
listTeams,
249+
listMyTeams,
234250
removeMember,
235251
removeModerator,
236252
updateMembers,

app/tests/api/team-api.test.js

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ test.before(async () => {
2020
await conn('users').insert({ id: 3 })
2121
await conn('users').insert({ id: 4 })
2222

23-
// Ensure authenticate middleware always goes through
24-
sinon.stub(permissions, 'can').callsFake(
25-
function () {
26-
return function (req, res, next) {
27-
res.locals.user_id = 1
28-
return next()
29-
}
23+
// Ensure authenticate middleware always goes through with user_id 1
24+
const middleware = function () {
25+
return function (req, res, next) {
26+
res.locals.user_id = 1
27+
return next()
3028
}
31-
)
29+
}
30+
sinon.stub(permissions, 'can').callsFake(middleware)
31+
sinon.stub(permissions, 'authenticate').callsFake(middleware)
32+
sinon.stub(permissions, 'check').callsFake(middleware)
3233

3334
// Ensure that resolveMemberNames never calls osm
3435
sinon.stub(team, 'resolveMemberNames').callsFake((ids) => {
@@ -241,3 +242,41 @@ test('remove moderator from team', async t => {
241242
const matchOsmIdAssigned = data => data.osm_id === osmId
242243
t.false(any(matchOsmIdAssigned, moderators))
243244
})
245+
246+
test('get my teams list', async t => {
247+
// get previous teams list for checking relative counts within this test.
248+
let response = await agent.get(`/api/my/teams`)
249+
.expect(200)
250+
const { member: prevMember, moderator: prevModerator } = response.body
251+
// create two more teams (osmId = 1)
252+
await agent.post('/api/teams')
253+
.send({ name: 'map team ♾+2' })
254+
.expect(200)
255+
const team = await agent.post('/api/teams')
256+
.send({ name: 'map team ♾+3' })
257+
.expect(200)
258+
const { id: teamId } = team.body
259+
// add osmId 2 to one team, and make them moderator
260+
await agent.put(`/api/teams/add/${teamId}/2`)
261+
.expect(200)
262+
await agent.put(`/api/teams/${teamId}/assignModerator/2`)
263+
.expect(200)
264+
// remove osmId 1 from moderator
265+
await agent.put(`/api/teams/${teamId}/removeModerator/1`)
266+
.expect(200)
267+
// check that osmId 1 is now +1 moderator and +2 member
268+
response = await agent.get(`/api/my/teams`)
269+
.expect(200)
270+
const { osmId, member, moderator } = response.body
271+
t.is(osmId, 1)
272+
t.is(moderator.length, prevModerator.length + 1)
273+
t.is(member.length, prevMember.length + 2)
274+
member.forEach(item => {
275+
t.truthy(item.name)
276+
t.truthy(item.id)
277+
})
278+
moderator.forEach(item => {
279+
t.truthy(item.name)
280+
t.truthy(item.id)
281+
})
282+
})

0 commit comments

Comments
 (0)