Skip to content

Commit 1afc278

Browse files
authored
Merge pull request #415 from developmentseed/feature/team-badge-column
Display organization badges on Team page
2 parents 4ca4ef3 + 83ae238 commit 1afc278

33 files changed

+1312
-578
lines changed

app/manage/index.js

-14
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,10 @@ const {
33
addMember,
44
assignModerator,
55
createTeam,
6-
destroyTeam,
7-
getTeam,
8-
getTeamMembers,
96
joinTeam,
107
listTeams,
118
removeMember,
129
removeModerator,
13-
updateMembers,
14-
updateTeam,
1510
getJoinInvitations,
1611
createJoinInvitation,
1712
deleteJoinInvitation,
@@ -66,17 +61,8 @@ function manageRouter(handler) {
6661
*/
6762
handler.get('/api/teams', listTeams)
6863
handler.post('/api/teams', can('public:authenticated'), createTeam)
69-
handler.get('/api/teams/:id', can('team:view'), getTeam)
70-
handler.get(
71-
'/api/teams/:id/members',
72-
can('team:view-members'),
73-
getTeamMembers
74-
)
75-
handler.put('/api/teams/:id', can('team:edit'), updateTeam)
76-
handler.delete('/api/teams/:id', can('team:edit'), destroyTeam)
7764
handler.put('/api/teams/add/:id/:osmId', can('team:edit'), addMember)
7865
handler.put('/api/teams/remove/:id/:osmId', can('team:edit'), removeMember)
79-
handler.patch('/api/teams/:id/members', can('team:edit'), updateMembers)
8066
handler.put('/api/teams/:id/join', can('team:join'), joinTeam)
8167
handler.put(
8268
'/api/teams/:id/assignModerator/:osmId',

app/manage/permissions/edit-org.js

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ const { isOwner } = require('../../../src/models/organization')
1212
* @returns {Promise<boolean>}
1313
*/
1414
async function editOrg(uid, { id }) {
15+
if (!uid) {
16+
return false
17+
}
1518
return isOwner(id, uid)
1619
}
1720

app/manage/permissions/index.js

-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ const keyPermissions = {
1515

1616
const teamPermissions = {
1717
'team:edit': require('./edit-team'),
18-
'team:view': require('./view-team'),
19-
'team:view-members': require('./view-team-members'),
2018
'team:join': require('./join-team'),
2119
'team:member': require('./member-team'),
2220
}

app/manage/permissions/view-team-members.js

-33
This file was deleted.

app/manage/permissions/view-team.js

-14
This file was deleted.

app/manage/teams.js

-137
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@ const db = require('../../src/lib/db')
33
const yup = require('yup')
44
const crypto = require('crypto')
55
const { routeWrapper } = require('./utils')
6-
const { prop, map, dissoc } = require('ramda')
76
const urlRegex = require('url-regex')
8-
const profile = require('../../src/models/profile')
97
const Boom = require('@hapi/boom')
108
const logger = require('../../src/lib/logger')
11-
129
const isUrl = urlRegex({ exact: true })
13-
const getOsmId = prop('osm_id')
1410

1511
async function listTeams(req, res) {
1612
const { osmId, bbox } = req.query
@@ -29,58 +25,6 @@ async function listTeams(req, res) {
2925
return res.send(data)
3026
}
3127

32-
async function getTeam(req, reply) {
33-
const { id } = req.params
34-
35-
if (!id) {
36-
throw Boom.badRequest('Team id is required')
37-
}
38-
39-
try {
40-
const teamData = await team.get(id)
41-
const associatedOrg = await team.associatedOrg(id)
42-
43-
if (!teamData) {
44-
throw Boom.notFound()
45-
}
46-
47-
return reply.send(Object.assign({}, teamData, { org: associatedOrg }))
48-
} catch (err) {
49-
logger.error(err)
50-
throw Boom.badRequest(err.message)
51-
}
52-
}
53-
54-
const getTeamMembers = routeWrapper({
55-
validate: {
56-
params: yup
57-
.object({
58-
id: yup.number().required().positive().integer(),
59-
})
60-
.required(),
61-
},
62-
handler: async (req, reply) => {
63-
const { id } = req.params
64-
65-
if (!id) {
66-
throw Boom.badRequest('team id is required')
67-
}
68-
69-
try {
70-
const memberIds = map(getOsmId, await team.getMembers(id))
71-
const members = await team.resolveMemberNames(memberIds)
72-
const moderators = await team.getModerators(id)
73-
74-
return reply.send(
75-
Object.assign({}, { teamId: id }, { members, moderators })
76-
)
77-
} catch (err) {
78-
logger.error(err)
79-
throw Boom.badRequest(err.message)
80-
}
81-
},
82-
})
83-
8428
async function createTeam(req, reply) {
8529
const { body } = req
8630
const { user_id } = req.session
@@ -97,35 +41,6 @@ async function createTeam(req, reply) {
9741
}
9842
}
9943

100-
async function updateTeam(req, reply) {
101-
const { id } = req.params
102-
const { body } = req
103-
104-
if (!id) {
105-
throw Boom.badRequest('team id is required')
106-
}
107-
108-
if (body.editing_policy && !isUrl.test(body.editing_policy)) {
109-
throw Boom.badRequest('editing_policy must be a valid url')
110-
}
111-
112-
try {
113-
const tags = prop('tags', body)
114-
if (tags) {
115-
await profile.setProfile(tags, 'team', id)
116-
}
117-
const teamData = dissoc('tags', body)
118-
let updatedTeam = {}
119-
if (teamData) {
120-
updatedTeam = await team.update(id, teamData)
121-
}
122-
reply.send(updatedTeam)
123-
} catch (err) {
124-
logger.error(err)
125-
throw Boom.badRequest(err.message)
126-
}
127-
}
128-
12944
async function assignModerator(req, reply) {
13045
const { id: teamId, osmId } = req.params
13146

@@ -170,22 +85,6 @@ async function removeModerator(req, reply) {
17085
}
17186
}
17287

173-
async function destroyTeam(req, reply) {
174-
const { id } = req.params
175-
176-
if (!id) {
177-
throw Boom.badRequest('team id is required')
178-
}
179-
180-
try {
181-
await team.destroy(id)
182-
return reply.status(200).send()
183-
} catch (err) {
184-
logger.error(err)
185-
throw Boom.badRequest(err.message)
186-
}
187-
}
188-
18988
async function addMember(req, reply) {
19089
const { id, osmId } = req.params
19190

@@ -206,37 +105,6 @@ async function addMember(req, reply) {
206105
}
207106
}
208107

209-
async function updateMembers(req, reply) {
210-
const { id } = req.params
211-
const { add, remove } = req.body
212-
213-
if (!id) {
214-
throw Boom.badRequest('team id is required')
215-
}
216-
217-
if (!add && !remove) {
218-
throw Boom.badRequest('osm ids are required')
219-
}
220-
221-
try {
222-
let members = []
223-
if (add) {
224-
members = members.concat(add)
225-
}
226-
if (remove) {
227-
members = members.concat(remove)
228-
}
229-
// Check if these are OSM users
230-
await team.resolveMemberNames(members)
231-
232-
await team.updateMembers(id, add, remove)
233-
return reply.status(200).send()
234-
} catch (err) {
235-
logger.error(err)
236-
throw Boom.badRequest(err.message)
237-
}
238-
}
239-
240108
async function removeMember(req, reply) {
241109
const { id, osmId } = req.params
242110

@@ -386,15 +254,10 @@ module.exports = {
386254
addMember,
387255
assignModerator,
388256
createTeam,
389-
destroyTeam,
390-
getTeam,
391-
getTeamMembers,
392257
joinTeam,
393258
listTeams,
394259
removeMember,
395260
removeModerator,
396-
updateMembers,
397-
updateTeam,
398261
getJoinInvitations,
399262
createJoinInvitation,
400263
deleteJoinInvitation,

cypress/e2e/organizations/badges.cy.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ describe('Organization page', () => {
9393
cy.visit('/organizations/1')
9494

9595
cy.get('[data-cy=org-members-table]')
96-
.find('tbody tr:nth-child(6) td:nth-child(3)')
96+
.find('tbody tr:nth-child(6) td:nth-child(2)')
9797
.contains('Badge 002')
9898
cy.get('[data-cy=org-members-table]')
99-
.find('tbody tr:nth-child(6) td:nth-child(3)')
99+
.find('tbody tr:nth-child(6) td:nth-child(2)')
100100
.contains('Badge 003')
101101
cy.get('[data-cy=org-members-table]')
102-
.find('tbody tr:nth-child(10) td:nth-child(3)')
102+
.find('tbody tr:nth-child(10) td:nth-child(2)')
103103
.contains('Badge 005')
104104
})
105105
})

public/static/osmcha-logo.svg

+1
Loading

src/components/badge.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function Badge({ color, dot, children }) {
1717
color={color}
1818
bg={`rgba(${hexToRgb(color)}, 0.125)`}
1919
size='sm'
20-
borderRadius={'full'}
20+
borderRadius={dot ? 'full' : 'sm'}
2121
boxShadow={`0 0 0 1px rgba(${hexToRgb(color)}, 0.25)`}
2222
mr={2}
2323
overflow='hidden'

src/components/external-profile-button.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const ExternalProfileButton = ({ type, userId }) => {
4343
title = 'View profile on OSMCha'
4444
label = 'OSMCha'
4545
altText = 'OSMCha Logo'
46-
logoImg = 'icon-osmcha-logo.svg'
46+
logoImg = 'osmcha-logo.svg'
4747
break
4848
default:
4949
return null
@@ -60,6 +60,7 @@ const ExternalProfileButton = ({ type, userId }) => {
6060
target='_blank'
6161
title={title}
6262
size='sm'
63+
bg='white'
6364
variant='ghost'
6465
>
6566
<img

src/components/pagination.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ function listPageOptions(page, lastPage) {
5151
}
5252

5353
function Pagination({ pagination, setPage, 'data-cy': dataCy }) {
54-
const { perPage, total, currentPage } = pagination
54+
let { perPage, total, currentPage, lastPage } = pagination
55+
currentPage = Number(currentPage)
5556

56-
const maxPages = perPage ? Math.ceil(total / perPage) : 0
57+
const maxPages = Number(lastPage)
5758
const pages = listPageOptions(currentPage + 1, maxPages)
5859

5960
return (
@@ -117,7 +118,9 @@ function Pagination({ pagination, setPage, 'data-cy': dataCy }) {
117118
<Text flexBasis='100%' width='100%' textAlign={'center'}>
118119
Showing {(currentPage - 1) * perPage + 1}-
119120
{Intl.NumberFormat().format(
120-
currentPage === maxPages ? total : currentPage * perPage
121+
Number(currentPage) === Number(maxPages)
122+
? total
123+
: currentPage * perPage
121124
)}{' '}
122125
of {Intl.NumberFormat().format(total)}
123126
</Text>

0 commit comments

Comments
 (0)