MapComplete/src/Logic/Maproulette.ts

120 lines
4.3 KiB
TypeScript

import Constants from "../Models/Constants"
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
import { ServerSourceInfo } from "../Models/SourceOverview"
export interface MaprouletteTask {
name: string
description: string
instruction: string
}
export const maprouletteStatus = [
"Open",
"Fixed",
"False_positive",
"Skipped",
"Deleted",
"Already fixed",
"Too_Hard",
"Disabled",
] as const
export type MaprouletteStatus = (typeof maprouletteStatus)[number]
export default class Maproulette {
public static readonly defaultEndpoint = "https://maproulette.org/api/v2"
public static readonly defaultEndpointInfo: ServerSourceInfo = {
url: Maproulette.defaultEndpoint,
trigger: ["specific_theme"],
category: "feature",
description:
"[MapRoulette](https://wiki.openstreetmap.org/wiki/MapRoulette) is a platform where tasks can be submitted, where every task contains some data about something that should be improved in OpenStreetMap. The intent is that those 'tasks' are solved by the community, effectively working as big, shared 'todo'-list. MapComplete can display such tasks and mark them solved. This is most often done to run an import of data.",
openData: true,
sourceAvailable: true,
selfhostable: true,
}
public static readonly STATUS_OPEN = 0
public static readonly STATUS_FIXED = 1
public static readonly STATUS_FALSE_POSITIVE = 2
public static readonly STATUS_SKIPPED = 3
public static readonly STATUS_DELETED = 4
public static readonly STATUS_ALREADY_FIXED = 5
public static readonly STATUS_TOO_HARD = 6
public static readonly STATUS_DISABLED = 9
public static singleton = new Maproulette()
/*
* The API endpoint to use
*/
endpoint: string
/**
* The API key to use for all requests
*/
private readonly apiKey: string
/**
* Creates a new Maproulette instance
* @param endpoint The API endpoint to use
*/
constructor(endpoint?: string) {
this.endpoint = endpoint ?? Maproulette.defaultEndpoint
if (!this.endpoint) {
throw "MapRoulette endpoint is undefined. Make sure that `Maproulette.defaultEndpoint` is defined on top of the class"
}
this.apiKey = Constants.MaprouletteApiKey
}
/**
* Converts a status text into the corresponding number
*
* Maproulette.codeToIndex("Created") // => 0
* Maproulette.codeToIndex("qdsf") // => undefined
*
*/
public static codeToIndex(code: string): number | undefined {
if (code === "Created") {
return Maproulette.STATUS_OPEN
}
const i = maprouletteStatus.indexOf(<any>code)
if (i < 0) {
return undefined
}
return i
}
/**
* Close a task; might throw an error
*
* Also see:https://maproulette.org/docs/swagger-ui/index.html?url=/assets/swagger.json&docExpansion=none#/Task/setTaskStatus
* @param taskId The task to close
* @param status A number indicating the status. Use MapRoulette.STATUS_*
* @param options Additional settings to pass. Refer to the API-docs for more information
*/
async closeTask(
taskId: number,
status = Maproulette.STATUS_FIXED,
state: SpecialVisualizationState,
options?: {
comment?: string
tags?: string
requestReview?: boolean
completionResponses?: Record<string, string>
}
): Promise<void> {
console.log("Maproulette: setting", `${this.endpoint}/task/${taskId}/${status}`, options)
options ??= {}
const userdetails = state.osmConnection.userDetails.data
options.tags = `MapComplete MapComplete:${state.theme.id}; userid: ${userdetails?.uid}; username: ${userdetails?.name}`
const response = await fetch(`${this.endpoint}/task/${taskId}/${status}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
apiKey: this.apiKey,
},
body: JSON.stringify(options),
})
if (response.status !== 204) {
console.log(`Failed to close task: ${response.status}`)
throw `Failed to close task: ${response.status}`
}
}
}