Skip to content

Commit 14713ac

Browse files
authored
Merge pull request #485 from OpenBeta/feature/update-single-climb
feat: add updateClimb mutation for editing a single climb by ID without parent area
2 parents 187af91 + c915a70 commit 14713ac

4 files changed

Lines changed: 73 additions & 0 deletions

File tree

src/auth/permissions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const permissions = shield({
1111
removeArea: isEditor,
1212
addArea: isEditor,
1313
updateArea: isEditor,
14+
updateClimb: isEditor,
1415
updateClimbs: isEditor,
1516
deleteClimbs: isEditor,
1617
bulkImportAreas: isEditor,

src/graphql/climb/ClimbMutations.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import muid, { MUUID } from 'uuid-mongodb'
22
import { ContextWithAuth } from '../../types.js'
3+
import { ClimbType } from '../../db/ClimbTypes.js'
34

45
const ClimbMutations = {
56
updateClimbs: async (_, { input }, { dataSources, user }: ContextWithAuth): Promise<string[]> => {
@@ -11,6 +12,15 @@ const ClimbMutations = {
1112
return await ds.addOrUpdateClimbs(user.uuid, muid.from(parentId), changes)
1213
},
1314

15+
updateClimb: async (_, { input }, { dataSources, user }: ContextWithAuth): Promise<ClimbType | null> => {
16+
const { climbs: ds } = dataSources
17+
const { id, ...changes } = input
18+
19+
if (user?.uuid == null) throw new Error('Missing user uuid')
20+
21+
return await ds.updateClimbById(user.uuid, muid.from(id), changes)
22+
},
23+
1424
deleteClimbs: async (_, { input }, { dataSources, user }: ContextWithAuth): Promise<number> => {
1525
const { climbs: ds } = dataSources
1626

src/graphql/schema/ClimbEdit.gql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ type Mutation {
44
"""
55
updateClimbs(input: UpdateClimbsInput): [ID]
66

7+
"""
8+
Update a single climb by its ID. Unlike updateClimbs, this doesn't require the parent area ID.
9+
"""
10+
updateClimb(input: SingleClimbInput!): Climb
11+
712
"""
813
Delete one or more climbs
914
"""
@@ -49,6 +54,30 @@ input SingleClimbChangeInput {
4954
experimentalAuthor: ExperimentalAuthorType
5055
}
5156

57+
"""
58+
Input for updating a single climb by its ID. The climb must already exist.
59+
"""
60+
input SingleClimbInput {
61+
"Climb UUID (required)"
62+
id: ID!
63+
name: String
64+
disciplines: DisciplineType
65+
grade: String
66+
leftRightIndex: Int
67+
description: String
68+
location: String
69+
protection: String
70+
"Legacy FA data"
71+
fa: String
72+
"Length in meters"
73+
length: Int
74+
"Number of fixed anchors"
75+
boltsCount: Int
76+
"List of Pitch objects representing individual pitches of a multi-pitch climb"
77+
pitches: [PitchInput]
78+
experimentalAuthor: ExperimentalAuthorType
79+
}
80+
5281
input GradeTypeInput {
5382
vscale: String
5483
yds: String

src/model/MutableClimbDataSource.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,39 @@ export default class MutableClimbDataSource extends ClimbDataSource {
285285
}
286286
}
287287

288+
/**
289+
* Update a single climb by its ID. Unlike addOrUpdateClimbs, this doesn't require the parent area ID.
290+
* @param userId User performing the action
291+
* @param climbId The climb's own ID
292+
* @param changes The fields to update
293+
* @returns The updated climb, or null if not found
294+
*/
295+
async updateClimbById (userId: MUUID, climbId: MUUID, changes: Omit<ClimbChangeInputType, 'id'>): Promise<ClimbType | null> {
296+
// Look up the climb to get its parent area ID
297+
const climb = await this.climbModel.findOne({ _id: climbId, _deleting: { $eq: null } }).lean()
298+
299+
if (climb == null) {
300+
throw new GraphQLError(`Climb with id: ${climbId.toUUID().toString()} not found`, {
301+
extensions: {
302+
code: ApolloServerErrorCode.BAD_USER_INPUT
303+
}
304+
})
305+
}
306+
307+
const parentId = climb.metadata.areaRef
308+
309+
// Use existing logic with the climb ID included
310+
const changeWithId: ClimbChangeInputType = {
311+
...changes,
312+
id: climbId.toUUID().toString()
313+
}
314+
315+
await this.addOrUpdateClimbs(userId, parentId, [changeWithId])
316+
317+
// Return the updated climb
318+
return await this.climbModel.findOne({ _id: climbId }).lean()
319+
}
320+
288321
/**
289322
* Delete one or more climbs by climb ID.
290323
* @param userId User performing the action

0 commit comments

Comments
 (0)