Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion app/lib/team.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,34 @@ async function list (options) {
return query
}

/**
* List the member osm ids for a list of team ids.
*
* @param {number[]} teamIds
* @returns {Promise<*>}
* @async
*/
async function listMembers (teamIds) {
const conn = await db()
return conn('member').whereIn('team_id', teamIds)
.join('users', 'member.osm_id', 'users.id')
.select('team_id', 'osm_id')
}

/**
* List the moderator osm ids for a list of team ids.
*
* @param {number[]} teamIds
* @returns {Promise<*>}
* @async
*/
async function listModerators (teamIds) {
const conn = await db()
return conn('moderator').whereIn('team_id', teamIds)
.join('users', 'moderator.osm_id', 'users.id')
.select('team_id', 'osm_id')
}

/**
* List all the teams which osm id is a moderator of.
*
Expand All @@ -134,7 +162,7 @@ async function listModeratedBy (osmId) {
*
* @param {object} data - params for a team
* @param {string} data.name - name of the team
* @param {geojson} data.location - lat/lon of team
* @param {geojson?} data.location - lat/lon of team
* @param {int} osmId - id of first moderator
* @param {object=} trx - optional parameter for database connection to re-use connection in case of nested
* transactions. This is used when a team is created as part of an organization
Expand Down Expand Up @@ -349,6 +377,8 @@ async function associatedOrg (teamId) {
module.exports = {
get,
list,
listMembers,
listModerators,
listModeratedBy,
create,
update,
Expand Down
4 changes: 3 additions & 1 deletion app/manage/organizations.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const organization = require('../lib/organization')
const team = require('../lib/team')
const { teamsMembersModeratorsHelper } = require('./utils')

/**
* Create an organization
Expand Down Expand Up @@ -200,7 +201,8 @@ async function getOrgTeams (req, reply) {
const { id } = req.params
try {
const data = await team.list({ organizationId: id })
reply.send(data)
const enhancedData = await teamsMembersModeratorsHelper(data)
reply.send(enhancedData)
} catch (err) {
console.log(err)
return reply.boom.badRequest(err.message)
Expand Down
7 changes: 5 additions & 2 deletions app/manage/teams.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const team = require('../lib/team')
const { prop, map } = require('ramda')
const urlRegex = require('url-regex')
const { teamsMembersModeratorsHelper } = require('./utils')

const isUrl = urlRegex({ exact: true })
const getOsmId = prop('osm_id')

async function listTeams (req, reply) {
const { osmId, bbox } = req.query
Expand All @@ -16,7 +18,8 @@ async function listTeams (req, reply) {

try {
const data = await team.list({ osmId, bbox: bounds })
reply.send(data)
const enhancedData = await teamsMembersModeratorsHelper(data)
reply.send(enhancedData)
} catch (err) {
console.log(err)
return reply.boom.badRequest(err.message)
Expand Down Expand Up @@ -48,7 +51,7 @@ async function getTeam (req, reply) {

try {
const teamData = await team.get(id)
const memberIds = map(prop('osm_id'), (await team.getMembers(id)))
const memberIds = map(getOsmId, (await team.getMembers(id)))
const members = await team.resolveMemberNames(memberIds)
const moderators = await team.getModerators(id)

Expand Down
33 changes: 33 additions & 0 deletions app/manage/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const team = require('../lib/team')
const { prop } = require('ramda')

const getId = prop('id')
const getOsmId = prop('osm_id')

/**
* Helper function for teams and organizations. Enhances teamsData with list of
* moderator ids and list of member ids.
*
* @param {Object[]} teamsData
* @returns {Promise<*>}
* @async
*/
async function teamsMembersModeratorsHelper (teamsData) {
const teamIds = teamsData.map(getId)
const [members, moderators] = await Promise.all([
team.listMembers(teamIds),
team.listModerators(teamIds)
])
return teamsData.map(team => {
const predicate = ({ team_id }) => team_id === team.id
return {
...team,
members: members.filter(predicate).map(getOsmId),
moderators: moderators.filter(predicate).map(getOsmId)
}
})
}

module.exports = {
teamsMembersModeratorsHelper
}
6 changes: 6 additions & 0 deletions app/tests/api/organization-api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,10 @@ test('get org teams', async t => {

const orgTeams = await agent.get(`/api/organizations/${res.body.id}/teams`)
t.is(orgTeams.body.length, 2)
orgTeams.body.forEach(item => {
t.truthy(item.name)
t.truthy(item.id)
t.truthy(item.members.length)
t.truthy(item.moderators.length)
})
})
2 changes: 2 additions & 0 deletions app/tests/api/team-api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ test('get team list', async t => {
teams.body.forEach(item => {
t.truthy(item.name)
t.truthy(item.id)
t.truthy(item.members.length)
t.truthy(item.moderators.length)
})
})

Expand Down
27 changes: 27 additions & 0 deletions app/tests/api/team-model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const path = require('path')
const test = require('ava')
const db = require('../../db')
const team = require('../../lib/team')
const { prop } = require('ramda')

const migrationsDirectory = path.join(__dirname, '..', '..', 'db', 'migrations')

Expand Down Expand Up @@ -57,6 +58,32 @@ test('list teams', async (t) => {
})
})

const getOsmId = prop('osm_id')

test('list team(s) members', async (t) => {
const team1 = await team.create({ name: 'list team members test' }, 1)
const team2 = await team.create({ name: 'list team members test2' }, 1)
await team.addMember(team2.id, 2)
const list = await team.listMembers([team1.id, team2.id])
const team1Members = list.filter(({ team_id }) => team_id === team1.id).map(getOsmId)
const team2Members = list.filter(({ team_id }) => team_id === team2.id).map(getOsmId)
t.deepEqual(team1Members, [1])
t.deepEqual(team2Members, [1, 2])
})

test('list team(s) moderators', async (t) => {
const team1 = await team.create({ name: 'list team mods test' }, 1)
const team2 = await team.create({ name: 'list team mods test2' }, 1)
await team.addMember(team2.id, 2)
await team.assignModerator(team2.id, 2)
await team.removeModerator(team2.id, 1)
const list = await team.listModerators([team1.id, team2.id])
const team1Mods = list.filter(({ team_id }) => team_id === team1.id).map(getOsmId)
const team2Mods = list.filter(({ team_id }) => team_id === team2.id).map(getOsmId)
t.deepEqual(team1Mods, [1])
t.deepEqual(team2Mods, [2])
})

test('update a team', async (t) => {
const data = await team.create({ name: 'poi team 1' }, 1)
const updated = await team.update(data.id, { name: 'road team 1' })
Expand Down
22 changes: 16 additions & 6 deletions docs/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ components:
type: string
format: uri
description: link to organized editing policy of the team
members:
type: array
description: list of team member's osm id
items:
type: number
moderators:
type: array
description: list of team member's osm id
items:
type: number
TeamList:
type: array
items:
Expand Down Expand Up @@ -503,7 +513,7 @@ paths:
moderator may exist concurrently. Moderators are listed in the
TeamModeratorList schema.
tags:
- teams
- teams
responses:
'200':
description: member was promoted to moderator
Expand All @@ -522,7 +532,7 @@ paths:
Remove/Demote a moderator of a team. At least one moderator must exist
for a team. Moderators are listed in the TeamModeratorList schema.
tags:
- teams
- teams
responses:
'200':
description: member was demoted from moderator
Expand Down Expand Up @@ -615,7 +625,7 @@ paths:
Assign/Promote a user to be an owner of an organization. More than one
owner may exist concurrently. Owners can manage organizations of an organization.
tags:
- organizations
- organizations
responses:
'200':
description: user is promoted to owner of organization
Expand All @@ -634,7 +644,7 @@ paths:
Remove/Demote an owner of an organization. At least one owner
must remain in the organization.
tags:
- organizations
- organizations
responses:
'200':
description: user is demoted from owner
Expand All @@ -654,7 +664,7 @@ paths:
manager may exist concurrently. Managers can create organizations for an organization
but cannot update the organization.
tags:
- organizations
- organizations
responses:
'200':
description: user is promoted to manager of organization
Expand All @@ -672,7 +682,7 @@ paths:
summary: >
Remove/Demote manager of an organization. An org can have no managers.
tags:
- organizations
- organizations
responses:
'200':
description: user is demoted from manager of organization
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
]
},
"dependencies": {
"ava": "^1.4.1",
"body-parser": "^1.18.3",
"chance": "^1.0.18",
"compression": "^1.7.3",
Expand Down Expand Up @@ -83,6 +82,7 @@
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"ava": "^3.7.0",
"babelify": "^10.0.0",
"budo": "^11.6.3",
"devseed-standard": "^1.1.0",
Expand Down
Loading