Skip to content

Commit

Permalink
feat: record author in add/updateArea if known (#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
vnugent committed Mar 14, 2023
1 parent 300a28b commit 0f61506
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/db/AreaTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BBox, Point } from '@turf/helpers'
import { ClimbType } from './ClimbTypes.js'
import { ChangeRecordMetadataType } from './ChangeLogType.js'
import { GradeContexts } from '../GradeUtils.js'
import { ExperimentalAuthorType } from './UserTypes.js'

/**
* Areas are a grouping mechanism in the OpenBeta data model that allow
Expand Down Expand Up @@ -165,6 +166,7 @@ export interface AreaEditableFieldsType {
shortCode?: string
lat?: number
lng?: number
experimentalAuthor?: ExperimentalAuthorType
}

export interface CountByGroupType {
Expand Down
5 changes: 5 additions & 0 deletions src/db/UserTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ export interface ExperimentalUserType {
createdAt: Date
updatedAt: Date
}

export interface ExperimentalAuthorType {
displayName: string
url: string
}
6 changes: 4 additions & 2 deletions src/graphql/area/AreaMutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ const AreaMutations = {

addArea: async (_, { input }, { dataSources, user }: ContextWithAuth): Promise<AreaType | null> => {
const { areas } = dataSources
const { name, parentUuid, countryCode } = input
const { name, parentUuid, countryCode, experimentalAuthor } = input

// permission middleware shouldn't send undefined uuid
if (user?.uuid == null) throw new Error('Missing user uuid')

return await areas.addArea(
user.uuid, name,
parentUuid == null ? null : muuid.from(parentUuid),
countryCode)
countryCode,
experimentalAuthor
)
},

updateArea: async (_, { input }, { dataSources, user }: ContextWithAuth): Promise<AreaType | null> => {
Expand Down
2 changes: 2 additions & 0 deletions src/graphql/schema/AreaEdit.gql
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ input AreaInput {
parentUuid: ID
countryCode: String
isDestination: Boolean
experimentalAuthor: ExperimentalAuthorType
}

input RemoveAreaInput {
Expand All @@ -44,4 +45,5 @@ input AreEditableFieldsInput {
lat: Float
lng: Float
description: String
experimentalAuthor: ExperimentalAuthorType
}
34 changes: 25 additions & 9 deletions src/model/MutableAreaDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ import CountriesLngLat from '../data/countries-with-lnglat.json' assert { type:
import { logger } from '../logger.js'
import { GradeContexts } from '../GradeUtils.js'
import { sanitizeStrict } from '../utils/sanitize.js'
import { ExperimentalAuthorType } from '../db/UserTypes.js'
import { createInstance as createExperimentalUserDataSource } from '../model/ExperimentalUserDataSource.js'

isoCountries.registerLocale(enJson)

export default class MutableAreaDataSource extends AreaDataSource {
experimentalUserDataSource = createExperimentalUserDataSource()

async setDestinationFlag (user: MUUID, uuid: MUUID, flag: boolean): Promise<AreaType | null> {
const session = await this.areaModel.startSession()
let ret: AreaType | null = null
Expand Down Expand Up @@ -101,7 +105,7 @@ export default class MutableAreaDataSource extends AreaDataSource {
* @param parentUuid
* @param countryCode
*/
async addArea (user: MUUID, areaName: string, parentUuid: MUUID | null, countryCode?: string): Promise<AreaType> {
async addArea (user: MUUID, areaName: string, parentUuid: MUUID | null, countryCode?: string, experimentalAuthor?: ExperimentalAuthorType): Promise<AreaType> {
if (parentUuid == null && countryCode == null) {
throw new Error('Adding area failed. Must provide parent Id or country code')
}
Expand All @@ -121,14 +125,14 @@ export default class MutableAreaDataSource extends AreaDataSource {
// see https://jira.mongodb.org/browse/NODE-2014
await session.withTransaction(
async (session) => {
ret = await this._addArea(session, user, areaName, uuid)
ret = await this._addArea(session, user, areaName, uuid, experimentalAuthor)
return ret
})
// @ts-expect-error
return ret
}

async _addArea (session, user: MUUID, areaName: string, parentUuid: MUUID): Promise<any> {
async _addArea (session, user: MUUID, areaName: string, parentUuid: MUUID, experimentalAuthor?: ExperimentalAuthorType): Promise<any> {
const parentFilter = { 'metadata.area_id': parentUuid }
const parent = await this.areaModel.findOne(parentFilter).session(session).orFail(new UserInputError('Expecting 1 parent, found none.'))

Expand All @@ -141,9 +145,15 @@ export default class MutableAreaDataSource extends AreaDataSource {
parent.metadata.isBoulder = false
}

// See https://github.com/OpenBeta/openbeta-graphql/issues/244
let experimentaAuthorId: MUUID | null = null
if (experimentalAuthor != null) {
experimentaAuthorId = await this.experimentalUserDataSource.updateUser(session, experimentalAuthor.displayName, experimentalAuthor.url)
}

const change = await changelogDataSource.create(session, user, OperationType.addArea)
const newChangeMeta: ChangeRecordMetadataType = {
user,
user: experimentaAuthorId ?? user,
historyId: change._id,
operation: OperationType.addArea,
seq: 0
Expand All @@ -159,15 +169,15 @@ export default class MutableAreaDataSource extends AreaDataSource {
const parentGradeContext = parent.gradeContext
const newArea = newAreaHelper(areaName, parentAncestors, parentPathTokens, parentGradeContext)
newArea.metadata.lnglat = parent.metadata.lnglat
newArea.createdBy = user
newArea.createdBy = experimentaAuthorId ?? user
newArea._change = produce(newChangeMeta, draft => {
draft.seq = 1
})
const rs1 = await this.areaModel.insertMany(newArea, { session })

// Make sure parent knows about this new area
parent.children.push(newArea._id)
parent.updatedBy = user
parent.updatedBy = experimentaAuthorId ?? user
await parent.save({ timestamps: false })
return rs1[0].toObject()
}
Expand Down Expand Up @@ -281,7 +291,7 @@ export default class MutableAreaDataSource extends AreaDataSource {
throw new Error('Area update error. Reason: Area not found.')
}

const { areaName, description, shortCode, isDestination, isLeaf, isBoulder, lat, lng } = document
const { areaName, description, shortCode, isDestination, isLeaf, isBoulder, lat, lng, experimentalAuthor } = document

if (area.pathTokens.length === 1) {
if (areaName != null || shortCode != null) throw new Error('Area update error. Reason: Updating country name or short code is not allowed.')
Expand Down Expand Up @@ -313,18 +323,24 @@ export default class MutableAreaDataSource extends AreaDataSource {
})
}

// See https://github.com/OpenBeta/openbeta-graphql/issues/244
let experimentaAuthorId: MUUID | null = null
if (experimentalAuthor != null) {
experimentaAuthorId = await this.experimentalUserDataSource.updateUser(session, experimentalAuthor.displayName, experimentalAuthor.url)
}

const opType = OperationType.updateArea
const change = await changelogDataSource.create(session, user, opType)

const _change: ChangeRecordMetadataType = {
user,
user: experimentaAuthorId ?? user,
historyId: change._id,
prevHistoryId: area._change?.historyId._id,
operation: opType,
seq: 0
}
area.set({ _change })
area.updatedBy = user
area.updatedBy = experimentaAuthorId ?? user
const cursor = await area.save()
return cursor.toObject()
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export const sanitizeStrict = (text: string): string => sanitizeHtml(text, {
allowedTags: [],
allowedAttributes: {
}
})
}).trim()

0 comments on commit 0f61506

Please sign in to comment.