Some cleanup of changesetHandler, add import source with reference to the note
This commit is contained in:
parent
7f222bce11
commit
5cefc4d25f
4 changed files with 129 additions and 55 deletions
|
@ -23,6 +23,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
private meta: { changeType: "create" | "import"; theme: string; specialMotivation?: string };
|
||||
private readonly _reusePreviouslyCreatedPoint: boolean;
|
||||
|
||||
|
||||
constructor(basicTags: Tag[],
|
||||
lat: number, lon: number,
|
||||
options: {
|
||||
|
@ -46,7 +47,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
this.meta = {
|
||||
theme: options.theme,
|
||||
changeType: options.changeType,
|
||||
|
||||
specialMotivation: options.specialMotivation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +68,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
}
|
||||
|
||||
async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
|
||||
|
||||
if (this._reusePreviouslyCreatedPoint) {
|
||||
|
||||
const key = this._lat + "," + this._lon
|
||||
|
@ -139,7 +141,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
|
||||
locations.splice(index + 1, 0, [this._lon, this._lat])
|
||||
ids.splice(index + 1, 0, id)
|
||||
|
||||
|
||||
// Allright, we have to insert a new point in the way
|
||||
return [
|
||||
newPointChange,
|
||||
|
|
|
@ -43,6 +43,30 @@ export class ChangesetHandler {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* If the metatags contain a special motivation of the format "<change-type>:node/-<number>", this method will rewrite this negative number to the actual ID
|
||||
* The key is changed _in place_; true will be returned if a change has been applied
|
||||
* @param extraMetaTags
|
||||
* @param rewriteIds
|
||||
* @private
|
||||
*/
|
||||
private static rewriteMetaTags(extraMetaTags: ChangesetTag[], rewriteIds: Map<string, string>) {
|
||||
let hasChange = false;
|
||||
for (const tag of extraMetaTags) {
|
||||
const match = tag.key.match(/^([a-zA-Z0-9_]+):(node\/-[0-9])$/)
|
||||
if (match == null) {
|
||||
continue
|
||||
}
|
||||
// This is a special motivation which has a negative ID -> we check for rewrites
|
||||
const [_, reason, id] = match
|
||||
if (rewriteIds.has(id)) {
|
||||
tag.key = reason + ":" + rewriteIds.get(id)
|
||||
hasChange = true
|
||||
}
|
||||
}
|
||||
return hasChange
|
||||
}
|
||||
|
||||
/**
|
||||
* The full logic to upload a change to one or more elements.
|
||||
*
|
||||
|
@ -81,7 +105,13 @@ export class ChangesetHandler {
|
|||
openChangeset.setData(csId);
|
||||
const changeset = generateChangeXML(csId);
|
||||
console.trace("Opened a new changeset (openChangeset.data is undefined):", changeset);
|
||||
await this.AddChange(csId, changeset)
|
||||
const changes = await this.AddChange(csId, changeset)
|
||||
const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
|
||||
if(hasSpecialMotivationChanges){
|
||||
// At this point, 'extraMetaTags' will have changed - we need to set the tags again
|
||||
this.UpdateTags(csId, extraMetaTags)
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error("Could not open/upload changeset due to ", e)
|
||||
openChangeset.setData(undefined)
|
||||
|
@ -91,6 +121,7 @@ export class ChangesetHandler {
|
|||
// Let's check!
|
||||
const csId = openChangeset.data;
|
||||
try {
|
||||
|
||||
const oldChangesetMeta = await this.GetChangesetMeta(csId)
|
||||
if (!oldChangesetMeta.open) {
|
||||
// Mark the CS as closed...
|
||||
|
@ -101,41 +132,11 @@ export class ChangesetHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
const extraTagsById = new Map<string, ChangesetTag>()
|
||||
for (const extraMetaTag of extraMetaTags) {
|
||||
extraTagsById.set(extraMetaTag.key, extraMetaTag)
|
||||
}
|
||||
const oldCsTags = oldChangesetMeta.tags
|
||||
for (const key in oldCsTags) {
|
||||
const newMetaTag = extraTagsById.get(key)
|
||||
if (newMetaTag === undefined) {
|
||||
extraMetaTags.push({
|
||||
key: key,
|
||||
value: oldCsTags[key]
|
||||
})
|
||||
} else if (newMetaTag.aggregate) {
|
||||
let n = Number(newMetaTag.value)
|
||||
if (isNaN(n)) {
|
||||
n = 0
|
||||
}
|
||||
let o = Number(oldCsTags[key])
|
||||
if (isNaN(o)) {
|
||||
o = 0
|
||||
}
|
||||
// We _update_ the tag itself, as it'll be updated in 'extraMetaTags' straight away
|
||||
newMetaTag.value = "" + (n + o)
|
||||
} else {
|
||||
// The old value is overwritten, thus we drop
|
||||
}
|
||||
}
|
||||
|
||||
await this.UpdateTags(csId, extraMetaTags.map(csTag => <[string, string]>[csTag.key, csTag.value]))
|
||||
|
||||
|
||||
await this.AddChange(
|
||||
const rewritings = await this.AddChange(
|
||||
csId,
|
||||
generateChangeXML(csId))
|
||||
|
||||
await this.RewriteTagsOf(extraMetaTags, rewritings, oldChangesetMeta)
|
||||
|
||||
} catch (e) {
|
||||
console.warn("Could not upload, changeset is probably closed: ", e);
|
||||
|
@ -144,6 +145,74 @@ export class ChangesetHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the metatag of a changeset -
|
||||
* @param extraMetaTags: new changeset tags to add/fuse with this changeset
|
||||
* @param oldChangesetMeta: the metadata-object of the already existing changeset
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
private async RewriteTagsOf(extraMetaTags: ChangesetTag[],
|
||||
rewriteIds: Map<string, string>,
|
||||
oldChangesetMeta: {
|
||||
open: boolean,
|
||||
id: number
|
||||
uid: number, // User ID
|
||||
changes_count: number,
|
||||
tags: any
|
||||
}) {
|
||||
|
||||
const csId = oldChangesetMeta.id
|
||||
|
||||
// Note: extraMetaTags is where all the tags are collected into
|
||||
|
||||
// same as 'extraMetaTag', but indexed
|
||||
// Note that updates to 'extraTagsById.get(<key>).value = XYZ' is shared with extraMetatags
|
||||
const extraTagsById = new Map<string, ChangesetTag>()
|
||||
for (const extraMetaTag of extraMetaTags) {
|
||||
extraTagsById.set(extraMetaTag.key, extraMetaTag)
|
||||
}
|
||||
|
||||
const oldCsTags = oldChangesetMeta.tags
|
||||
for (const key in oldCsTags) {
|
||||
const newMetaTag = extraTagsById.get(key)
|
||||
const existingValue = oldCsTags[key]
|
||||
|
||||
if (newMetaTag !== undefined && newMetaTag.value === existingValue) {
|
||||
continue
|
||||
}
|
||||
if (newMetaTag === undefined) {
|
||||
extraMetaTags.push({
|
||||
key: key,
|
||||
value: oldCsTags[key]
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if (newMetaTag.aggregate) {
|
||||
let n = Number(newMetaTag.value)
|
||||
if (isNaN(n)) {
|
||||
n = 0
|
||||
}
|
||||
let o = Number(oldCsTags[key])
|
||||
if (isNaN(o)) {
|
||||
o = 0
|
||||
}
|
||||
// We _update_ the tag itself, as it'll be updated in 'extraMetaTags' straight away
|
||||
newMetaTag.value = "" + (n + o)
|
||||
} else {
|
||||
// The old value is overwritten, thus we drop this old key
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChangesetHandler.rewriteMetaTags(extraMetaTags, rewriteIds)
|
||||
|
||||
await this.UpdateTags(csId, extraMetaTags)
|
||||
|
||||
|
||||
}
|
||||
|
||||
private handleIdRewrite(node: any, type: string): [string, string] {
|
||||
const oldId = parseInt(node.attributes.old_id.value);
|
||||
if (node.attributes.new_id === undefined) {
|
||||
|
@ -163,7 +232,6 @@ export class ChangesetHandler {
|
|||
if (oldId == newId) {
|
||||
return undefined;
|
||||
}
|
||||
console.log("Rewriting id: ", type + "/" + oldId, "-->", type + "/" + newId);
|
||||
const element = this.allElements.getEventSourceById("node/" + oldId);
|
||||
if (element === undefined) {
|
||||
// Element to rewrite not found, probably a node or relation that is not rendered
|
||||
|
@ -176,7 +244,7 @@ export class ChangesetHandler {
|
|||
return result;
|
||||
}
|
||||
|
||||
private parseUploadChangesetResponse(response: XMLDocument): void {
|
||||
private parseUploadChangesetResponse(response: XMLDocument): Map<string, string> {
|
||||
const nodes = response.getElementsByTagName("node");
|
||||
const mappings = new Map<string, string>()
|
||||
// @ts-ignore
|
||||
|
@ -196,6 +264,7 @@ export class ChangesetHandler {
|
|||
}
|
||||
}
|
||||
this.changes.registerIdRewrites(mappings)
|
||||
return mappings
|
||||
|
||||
}
|
||||
|
||||
|
@ -205,7 +274,6 @@ export class ChangesetHandler {
|
|||
if (changesetId === undefined) {
|
||||
return;
|
||||
}
|
||||
console.log("closing changeset", changesetId);
|
||||
self.auth.xhr({
|
||||
method: 'PUT',
|
||||
path: '/api/0.6/changeset/' + changesetId + '/close',
|
||||
|
@ -232,15 +300,21 @@ export class ChangesetHandler {
|
|||
return csData.elements[0]
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Puts the specified tags onto the changesets as they are.
|
||||
* This method will erase previously set tags
|
||||
*/
|
||||
private async UpdateTags(
|
||||
csId: number,
|
||||
tags: [string, string][]) {
|
||||
tags: ChangesetTag[]) {
|
||||
|
||||
console.trace("Updating tags of " + csId)
|
||||
const self = this;
|
||||
return new Promise<string>(function (resolve, reject) {
|
||||
|
||||
tags = Utils.NoNull(tags).filter(([k, v]) => k !== undefined && v !== undefined && k !== "" && v !== "")
|
||||
const metadata = tags.map(kv => `<tag k="${kv[0]}" v="${escapeHtml(kv[1])}"/>`)
|
||||
tags = Utils.NoNull(tags).filter(tag => tag.key !== undefined && tag.value !== undefined && tag.key !== "" && tag.value !== "")
|
||||
const metadata = tags.map(kv => `<tag k="${kv.key}" v="${escapeHtml(kv.value)}"/>`)
|
||||
|
||||
self.auth.xhr({
|
||||
method: 'PUT',
|
||||
|
@ -258,7 +332,6 @@ export class ChangesetHandler {
|
|||
}
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private OpenChangeset(
|
||||
|
@ -306,7 +379,7 @@ export class ChangesetHandler {
|
|||
* Upload a changesetXML
|
||||
*/
|
||||
private AddChange(changesetId: number,
|
||||
changesetXML: string): Promise<number> {
|
||||
changesetXML: string): Promise<Map<string, string>> {
|
||||
const self = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
self.auth.xhr({
|
||||
|
@ -319,9 +392,9 @@ export class ChangesetHandler {
|
|||
console.log("err", err);
|
||||
reject(err);
|
||||
}
|
||||
self.parseUploadChangesetResponse(response);
|
||||
const changes = self.parseUploadChangesetResponse(response);
|
||||
console.log("Uploaded changeset ", changesetId);
|
||||
resolve(changesetId);
|
||||
resolve(changes);
|
||||
});
|
||||
})
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ export default class FilterView extends VariableUiElement {
|
|||
|
||||
const style =
|
||||
"display:flex;align-items:center;padding:0.5rem 0;";
|
||||
const layerIcon = layer.defaultIcon()?.SetClass("w-8 h-8 ml-2")
|
||||
const layerIcon = layer.defaultIcon()?.SetClass("w-8 h-8 ml-2 shrink-0")
|
||||
const layerIconUnchecked = layer.defaultIcon()?.SetClass("opacity-50 w-8 h-8 ml-2")
|
||||
|
||||
const layerChecked = new Combine([icon, layerIcon, styledNameChecked, zoomStatus])
|
||||
|
|
|
@ -523,26 +523,25 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
snapOnto = await OsmObject.DownloadObjectAsync(snapOntoWayId)
|
||||
}
|
||||
let specialMotivation = undefined
|
||||
if (args.note_id !== undefined) {
|
||||
specialMotivation = "source: https://osm.org/note/" + args.note_id
|
||||
|
||||
let note_id = args.note_id
|
||||
if (args.note_id !== undefined && isNaN(Number(args.note_id))) {
|
||||
note_id = originalFeatureTags.data[args.note_id]
|
||||
specialMotivation = "source: https://osm.org/note/" + note_id
|
||||
}
|
||||
|
||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||
theme: state.layoutToUse.id,
|
||||
changeType: "import",
|
||||
snapOnto: <OsmWay>snapOnto,
|
||||
specialMotivation
|
||||
specialMotivation: specialMotivation
|
||||
})
|
||||
|
||||
await state.changes.applyAction(newElementAction)
|
||||
state.selectedElement.setData(state.allElements.ContainingFeatures.get(
|
||||
newElementAction.newElementId
|
||||
))
|
||||
if (args.note_id !== undefined) {
|
||||
let note_id = args.note_id
|
||||
if (isNaN(Number(args.note_id))) {
|
||||
note_id = originalFeatureTags.data[args.note_id]
|
||||
}
|
||||
|
||||
if (note_id !== undefined) {
|
||||
state.osmConnection.closeNote(note_id, "imported")
|
||||
originalFeatureTags.data["closed_at"] = new Date().toISOString()
|
||||
originalFeatureTags.ping()
|
||||
|
|
Loading…
Reference in a new issue