forked from MapComplete/MapComplete
Refactoring: move all code files into a src directory
This commit is contained in:
parent
de99f56ca8
commit
e75d2789d2
389 changed files with 0 additions and 12 deletions
187
src/UI/Popup/DeleteFlow/DeleteFlowState.ts
Normal file
187
src/UI/Popup/DeleteFlow/DeleteFlowState.ts
Normal file
|
@ -0,0 +1,187 @@
|
|||
import { Translation } from "../../i18n/Translation"
|
||||
import OsmObjectDownloader from "../../../Logic/Osm/OsmObjectDownloader"
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import { OsmId } from "../../../Models/OsmFeature"
|
||||
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
|
||||
import { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import Translations from "../../i18n/Translations"
|
||||
import Constants from "../../../Models/Constants"
|
||||
|
||||
export class DeleteFlowState {
|
||||
public readonly canBeDeleted: UIEventSource<boolean | undefined> = new UIEventSource<
|
||||
boolean | undefined
|
||||
>(undefined)
|
||||
public readonly canBeDeletedReason: UIEventSource<Translation | undefined> =
|
||||
new UIEventSource<Translation>(undefined)
|
||||
private readonly objectDownloader: OsmObjectDownloader
|
||||
private readonly _id: OsmId
|
||||
private readonly _allowDeletionAtChangesetCount: number
|
||||
private readonly _osmConnection: OsmConnection
|
||||
private readonly state: SpecialVisualizationState
|
||||
|
||||
constructor(
|
||||
id: OsmId,
|
||||
state: SpecialVisualizationState,
|
||||
allowDeletionAtChangesetCount?: number
|
||||
) {
|
||||
this.state = state
|
||||
this.objectDownloader = state.osmObjectDownloader
|
||||
this._id = id
|
||||
this._osmConnection = state.osmConnection
|
||||
this._allowDeletionAtChangesetCount = allowDeletionAtChangesetCount ?? Number.MAX_VALUE
|
||||
|
||||
this.CheckDeleteability(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the currently logged in user can delete the current point.
|
||||
* State is written into this._canBeDeleted
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
public CheckDeleteability(useTheInternet: boolean): void {
|
||||
console.log("Checking deleteability (internet?", useTheInternet, ")")
|
||||
const t = Translations.t.delete
|
||||
const id = this._id
|
||||
const self = this
|
||||
if (!id.startsWith("node")) {
|
||||
this.canBeDeleted.setData(false)
|
||||
this.canBeDeletedReason.setData(t.isntAPoint)
|
||||
return
|
||||
}
|
||||
|
||||
// Does the currently logged in user have enough experience to delete this point?
|
||||
const deletingPointsOfOtherAllowed = this._osmConnection.userDetails.map((ud) => {
|
||||
if (ud === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (!ud.loggedIn) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
ud.csCount >=
|
||||
Math.min(
|
||||
Constants.userJourney.deletePointsOfOthersUnlock,
|
||||
this._allowDeletionAtChangesetCount
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
const previousEditors = new UIEventSource<number[]>(undefined)
|
||||
const allByMyself = previousEditors.map(
|
||||
(previous) => {
|
||||
if (previous === null || previous === undefined) {
|
||||
// Not yet downloaded
|
||||
return null
|
||||
}
|
||||
const userId = self._osmConnection.userDetails.data.uid
|
||||
return !previous.some((editor) => editor !== userId)
|
||||
},
|
||||
[self._osmConnection.userDetails]
|
||||
)
|
||||
|
||||
// User allowed OR only edited by self?
|
||||
const deletetionAllowed = deletingPointsOfOtherAllowed.map(
|
||||
(isAllowed) => {
|
||||
if (isAllowed === undefined) {
|
||||
// No logged in user => definitively not allowed to delete!
|
||||
return false
|
||||
}
|
||||
if (isAllowed === true) {
|
||||
return true
|
||||
}
|
||||
|
||||
// At this point, the logged in user is not allowed to delete points created/edited by _others_
|
||||
// however, we query OSM and if it turns out the current point has only be edited by the current user, deletion is allowed after all!
|
||||
|
||||
if (allByMyself.data === null && useTheInternet) {
|
||||
// We kickoff the download here as it hasn't yet been downloaded. Note that this is mapped onto 'all by myself' above
|
||||
const hist = this.objectDownloader
|
||||
.DownloadHistory(id)
|
||||
.map((versions) =>
|
||||
versions.map((version) =>
|
||||
Number(version.tags["_last_edit:contributor:uid"])
|
||||
)
|
||||
)
|
||||
hist.addCallbackAndRunD((hist) => previousEditors.setData(hist))
|
||||
}
|
||||
|
||||
if (allByMyself.data === true) {
|
||||
// Yay! We can download!
|
||||
return true
|
||||
}
|
||||
if (allByMyself.data === false) {
|
||||
// Nope, downloading not allowed...
|
||||
return false
|
||||
}
|
||||
|
||||
// At this point, we don't have enough information yet to decide if the user is allowed to delete the current point...
|
||||
return undefined
|
||||
},
|
||||
[allByMyself]
|
||||
)
|
||||
|
||||
const hasRelations: UIEventSource<boolean> = new UIEventSource<boolean>(null)
|
||||
const hasWays: UIEventSource<boolean> = new UIEventSource<boolean>(null)
|
||||
deletetionAllowed.addCallbackAndRunD((deletetionAllowed) => {
|
||||
if (deletetionAllowed === false) {
|
||||
// Nope, we are not allowed to delete
|
||||
|
||||
this.canBeDeleted.setData(false)
|
||||
this.canBeDeletedReason.setData(t.notEnoughExperience)
|
||||
return true // unregister this caller!
|
||||
}
|
||||
|
||||
if (!useTheInternet) {
|
||||
return
|
||||
}
|
||||
|
||||
// All right! We have arrived at a point that we should query OSM again to check that the point isn't a part of ways or relations
|
||||
this.objectDownloader.DownloadReferencingRelations(id).then((rels) => {
|
||||
hasRelations.setData(rels.length > 0)
|
||||
})
|
||||
|
||||
this.objectDownloader.DownloadReferencingWays(id).then((ways) => {
|
||||
hasWays.setData(ways.length > 0)
|
||||
})
|
||||
return true // unregister to only run once
|
||||
})
|
||||
|
||||
const hasWaysOrRelations = hasRelations.map(
|
||||
(hasRelationsData) => {
|
||||
if (hasRelationsData === true) {
|
||||
return true
|
||||
}
|
||||
if (hasWays.data === true) {
|
||||
return true
|
||||
}
|
||||
if (hasWays.data === null || hasRelationsData === null) {
|
||||
return null
|
||||
}
|
||||
if (hasWays.data === false && hasRelationsData === false) {
|
||||
return false
|
||||
}
|
||||
return null
|
||||
},
|
||||
[hasWays]
|
||||
)
|
||||
|
||||
hasWaysOrRelations.addCallbackAndRun((waysOrRelations) => {
|
||||
if (waysOrRelations == null) {
|
||||
// Not yet loaded - we still wait a little bit
|
||||
return
|
||||
}
|
||||
if (waysOrRelations) {
|
||||
// not deleteable by mapcomplete
|
||||
this.canBeDeleted.setData(false)
|
||||
this.canBeDeletedReason.setData(t.partOfOthers)
|
||||
} else {
|
||||
// alright, this point can be safely deleted!
|
||||
this.canBeDeleted.setData(true)
|
||||
this.canBeDeletedReason.setData(
|
||||
allByMyself.data ? t.onlyEditedByLoggedInUser : t.safeDelete
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue