Add switches to enable some more privacy, fix all errors in osmAuth
This commit is contained in:
parent
a856d8edc9
commit
fbf23b6e18
6 changed files with 128 additions and 132 deletions
|
@ -484,6 +484,41 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "more_privacy_theme_override",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "__featureSwitchMorePrivacy=true",
|
||||||
|
"then": {
|
||||||
|
"en": "This theme is sensitive. Making changes will not indicate if you were nearby explicitly."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "more_privacy",
|
||||||
|
"question":
|
||||||
|
{
|
||||||
|
"en": "When making changes, should a rough indication be given how far away you were from the object?"
|
||||||
|
},
|
||||||
|
"questionHint": {
|
||||||
|
"en": "If you make a change to one or more objects and you enabled your location, a rough indication of where you made will be saved: it is indicated if you were closer then 25m, 500m, 5km or further away then 5km. This helps mappers understand your context when making changes, but gives an indication of where you were at this time. "
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "mapcomplete-more_privacy=yes",
|
||||||
|
"then": {
|
||||||
|
"en": "When making changes to OpenStreetMap, do not indicate how far away you were from the changed objects."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "mapcomplete-more_privacy=no",
|
||||||
|
"then": {
|
||||||
|
"en": "When making changes to OpenStreetMap, roughly indicate how far away you were from the changed objects. This helps other contributors to understand how you made the change"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "mangrove-keys",
|
"id": "mangrove-keys",
|
||||||
"render": {
|
"render": {
|
||||||
|
|
29
package-lock.json
generated
29
package-lock.json
generated
|
@ -55,7 +55,7 @@
|
||||||
"monaco-editor": "^0.46.0",
|
"monaco-editor": "^0.46.0",
|
||||||
"npm": "^10.7.0",
|
"npm": "^10.7.0",
|
||||||
"opening_hours": "^3.6.0",
|
"opening_hours": "^3.6.0",
|
||||||
"osm-auth": "^2.2.0",
|
"osm-auth": "^2.5.0",
|
||||||
"osmtogeojson": "^3.0.0-beta.5",
|
"osmtogeojson": "^3.0.0-beta.5",
|
||||||
"panzoom": "^9.4.3",
|
"panzoom": "^9.4.3",
|
||||||
"papaparse": "^5.3.1",
|
"papaparse": "^5.3.1",
|
||||||
|
@ -14631,13 +14631,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/osm-auth": {
|
"node_modules/osm-auth": {
|
||||||
"version": "2.2.0",
|
"version": "2.5.0",
|
||||||
"license": "ISC",
|
"resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-2.5.0.tgz",
|
||||||
"dependencies": {
|
"integrity": "sha512-w3NnYbt+0PIih2Kwr1sLfQWehdLbcA3gZNJhX4VOBfeRtvm30iZA3nURphuZDokZ8Kmdv4LWB+AiIng2b+KvIA==",
|
||||||
"store": "~2.0.12"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=18.18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/osm-polygon-features": {
|
"node_modules/osm-polygon-features": {
|
||||||
|
@ -17081,13 +17079,6 @@
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/store": {
|
|
||||||
"version": "2.0.12",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/stream-to-string": {
|
"node_modules/stream-to-string": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -29202,10 +29193,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"osm-auth": {
|
"osm-auth": {
|
||||||
"version": "2.2.0",
|
"version": "2.5.0",
|
||||||
"requires": {
|
"resolved": "https://registry.npmjs.org/osm-auth/-/osm-auth-2.5.0.tgz",
|
||||||
"store": "~2.0.12"
|
"integrity": "sha512-w3NnYbt+0PIih2Kwr1sLfQWehdLbcA3gZNJhX4VOBfeRtvm30iZA3nURphuZDokZ8Kmdv4LWB+AiIng2b+KvIA=="
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"osm-polygon-features": {
|
"osm-polygon-features": {
|
||||||
"version": "0.9.2"
|
"version": "0.9.2"
|
||||||
|
@ -30803,9 +30793,6 @@
|
||||||
"std-env": {
|
"std-env": {
|
||||||
"version": "3.3.2"
|
"version": "3.3.2"
|
||||||
},
|
},
|
||||||
"store": {
|
|
||||||
"version": "2.0.12"
|
|
||||||
},
|
|
||||||
"stream-to-string": {
|
"stream-to-string": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|
|
@ -173,7 +173,7 @@
|
||||||
"monaco-editor": "^0.46.0",
|
"monaco-editor": "^0.46.0",
|
||||||
"npm": "^10.7.0",
|
"npm": "^10.7.0",
|
||||||
"opening_hours": "^3.6.0",
|
"opening_hours": "^3.6.0",
|
||||||
"osm-auth": "^2.2.0",
|
"osm-auth": "^2.5.0",
|
||||||
"osmtogeojson": "^3.0.0-beta.5",
|
"osmtogeojson": "^3.0.0-beta.5",
|
||||||
"panzoom": "^9.4.3",
|
"panzoom": "^9.4.3",
|
||||||
"papaparse": "^5.3.1",
|
"papaparse": "^5.3.1",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// @ts-ignore
|
|
||||||
import { osmAuth } from "osm-auth"
|
import { osmAuth } from "osm-auth"
|
||||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||||
import { OsmPreferences } from "./OsmPreferences"
|
import { OsmPreferences } from "./OsmPreferences"
|
||||||
|
@ -6,7 +5,18 @@ import { Utils } from "../../Utils"
|
||||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import { AuthConfig } from "./AuthConfig"
|
import { AuthConfig } from "./AuthConfig"
|
||||||
import Constants from "../../Models/Constants"
|
import Constants from "../../Models/Constants"
|
||||||
import OSMAuthInstance = OSMAuth.OSMAuthInstance
|
|
||||||
|
interface OsmUserInfo {
|
||||||
|
id: number
|
||||||
|
display_name: string
|
||||||
|
account_created: string
|
||||||
|
description: string
|
||||||
|
contributor_terms: { agreed: boolean }
|
||||||
|
roles: []
|
||||||
|
changesets: { count: number }
|
||||||
|
traces: { count: number }
|
||||||
|
blocks: { received: { count: number; active: number } }
|
||||||
|
}
|
||||||
|
|
||||||
export default class UserDetails {
|
export default class UserDetails {
|
||||||
public loggedIn = false
|
public loggedIn = false
|
||||||
|
@ -31,7 +41,7 @@ export default class UserDetails {
|
||||||
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
||||||
|
|
||||||
export class OsmConnection {
|
export class OsmConnection {
|
||||||
public auth: OSMAuthInstance
|
public auth: osmAuth
|
||||||
public userDetails: UIEventSource<UserDetails>
|
public userDetails: UIEventSource<UserDetails>
|
||||||
public isLoggedIn: Store<boolean>
|
public isLoggedIn: Store<boolean>
|
||||||
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||||
|
@ -49,7 +59,7 @@ export class OsmConnection {
|
||||||
private readonly _dryRun: Store<boolean>
|
private readonly _dryRun: Store<boolean>
|
||||||
private readonly fakeUser: boolean
|
private readonly fakeUser: boolean
|
||||||
private _onLoggedIn: ((userDetails: UserDetails) => void)[] = []
|
private _onLoggedIn: ((userDetails: UserDetails) => void)[] = []
|
||||||
private readonly _iframeMode: Boolean | boolean
|
private readonly _iframeMode: boolean
|
||||||
private readonly _singlePage: boolean
|
private readonly _singlePage: boolean
|
||||||
private isChecking = false
|
private isChecking = false
|
||||||
private readonly _doCheckRegularly
|
private readonly _doCheckRegularly
|
||||||
|
@ -99,20 +109,19 @@ export class OsmConnection {
|
||||||
ud.languages = ["en"]
|
ud.languages = ["en"]
|
||||||
this.loadingStatus.setData("logged-in")
|
this.loadingStatus.setData("logged-in")
|
||||||
}
|
}
|
||||||
const self = this
|
|
||||||
this.UpdateCapabilities()
|
this.UpdateCapabilities()
|
||||||
|
|
||||||
this.isLoggedIn = this.userDetails.map(
|
this.isLoggedIn = this.userDetails.map(
|
||||||
(user) =>
|
(user) =>
|
||||||
user.loggedIn &&
|
user.loggedIn &&
|
||||||
(self.apiIsOnline.data === "unknown" || self.apiIsOnline.data === "online"),
|
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
||||||
[this.apiIsOnline]
|
[this.apiIsOnline]
|
||||||
)
|
)
|
||||||
this.isLoggedIn.addCallback((isLoggedIn) => {
|
this.isLoggedIn.addCallback((isLoggedIn) => {
|
||||||
if (self.userDetails.data.loggedIn == false && isLoggedIn == true) {
|
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
|
||||||
// We have an inconsistency: the userdetails say we _didn't_ log in, but this actor says we do
|
// We have an inconsistency: the userdetails say we _didn't_ log in, but this actor says we do
|
||||||
// This means someone attempted to toggle this; so we attempt to login!
|
// This means someone attempted to toggle this; so we attempt to login!
|
||||||
self.AttemptLogin()
|
this.AttemptLogin()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -120,17 +129,16 @@ export class OsmConnection {
|
||||||
|
|
||||||
this.updateAuthObject()
|
this.updateAuthObject()
|
||||||
if (!this.fakeUser) {
|
if (!this.fakeUser) {
|
||||||
self.CheckForMessagesContinuously()
|
this.CheckForMessagesContinuously()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.preferencesHandler = new OsmPreferences(this.auth, this, this.fakeUser)
|
this.preferencesHandler = new OsmPreferences(this.auth, this, this.fakeUser)
|
||||||
|
|
||||||
if (options.oauth_token?.data !== undefined) {
|
if (options.oauth_token?.data !== undefined) {
|
||||||
console.log(options.oauth_token.data)
|
console.log(options.oauth_token.data)
|
||||||
const self = this
|
|
||||||
this.auth.bootstrapToken(options.oauth_token.data, (err, result) => {
|
this.auth.bootstrapToken(options.oauth_token.data, (err, result) => {
|
||||||
console.log("Bootstrap token called back", err, result)
|
console.log("Bootstrap token called back", err, result)
|
||||||
self.AttemptLogin()
|
this.AttemptLogin()
|
||||||
})
|
})
|
||||||
|
|
||||||
options.oauth_token.setData(undefined)
|
options.oauth_token.setData(undefined)
|
||||||
|
@ -142,15 +150,15 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GetPreference(
|
public GetPreference<T extends string = string>(
|
||||||
key: string,
|
key: string,
|
||||||
defaultValue: string = undefined,
|
defaultValue: string = undefined,
|
||||||
options?: {
|
options?: {
|
||||||
documentation?: string
|
documentation?: string
|
||||||
prefix?: string
|
prefix?: string
|
||||||
}
|
}
|
||||||
): UIEventSource<string> {
|
): UIEventSource<T | undefined> {
|
||||||
return this.preferencesHandler.GetPreference(key, defaultValue, options)
|
return <UIEventSource<T>>this.preferencesHandler.GetPreference(key, defaultValue, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
public GetLongPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
|
public GetLongPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
|
||||||
|
@ -192,7 +200,7 @@ export class OsmConnection {
|
||||||
console.log("AttemptLogin called, but ignored as fakeUser is set")
|
console.log("AttemptLogin called, but ignored as fakeUser is set")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const self = this
|
|
||||||
console.log("Trying to log in...")
|
console.log("Trying to log in...")
|
||||||
this.updateAuthObject()
|
this.updateAuthObject()
|
||||||
|
|
||||||
|
@ -202,33 +210,33 @@ export class OsmConnection {
|
||||||
this.auth.xhr(
|
this.auth.xhr(
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/api/0.6/user/details",
|
path: "/api/0.6/user/details"
|
||||||
},
|
},
|
||||||
function (err, details: XMLDocument) {
|
(err, details: XMLDocument) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
console.log("Could not login due to:", err)
|
console.log("Could not login due to:", err)
|
||||||
self.loadingStatus.setData("error")
|
this.loadingStatus.setData("error")
|
||||||
if (err.status == 401) {
|
if (err.status == 401) {
|
||||||
console.log("Clearing tokens...")
|
console.log("Clearing tokens...")
|
||||||
// Not authorized - our token probably got revoked
|
// Not authorized - our token probably got revoked
|
||||||
self.auth.logout()
|
this.auth.logout()
|
||||||
self.LogOut()
|
this.LogOut()
|
||||||
} else {
|
} else {
|
||||||
console.log("Other error. Status:", err.status)
|
console.log("Other error. Status:", err.status)
|
||||||
self.apiIsOnline.setData("unreachable")
|
this.apiIsOnline.setData("unreachable")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details == null) {
|
if (details == null) {
|
||||||
self.loadingStatus.setData("error")
|
this.loadingStatus.setData("error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// details is an XML DOM of user details
|
// details is an XML DOM of user details
|
||||||
let userInfo = details.getElementsByTagName("user")[0]
|
const userInfo = details.getElementsByTagName("user")[0]
|
||||||
|
|
||||||
let data = self.userDetails.data
|
const data = this.userDetails.data
|
||||||
data.loggedIn = true
|
data.loggedIn = true
|
||||||
console.log("Login completed, userinfo is ", userInfo)
|
console.log("Login completed, userinfo is ", userInfo)
|
||||||
data.name = userInfo.getAttribute("display_name")
|
data.name = userInfo.getAttribute("display_name")
|
||||||
|
@ -261,18 +269,18 @@ export class OsmConnection {
|
||||||
data.home = { lat: lat, lon: lon }
|
data.home = { lat: lat, lon: lon }
|
||||||
}
|
}
|
||||||
|
|
||||||
self.loadingStatus.setData("logged-in")
|
this.loadingStatus.setData("logged-in")
|
||||||
const messages = userInfo
|
const messages = userInfo
|
||||||
.getElementsByTagName("messages")[0]
|
.getElementsByTagName("messages")[0]
|
||||||
.getElementsByTagName("received")[0]
|
.getElementsByTagName("received")[0]
|
||||||
data.unreadMessages = parseInt(messages.getAttribute("unread"))
|
data.unreadMessages = parseInt(messages.getAttribute("unread"))
|
||||||
data.totalMessages = parseInt(messages.getAttribute("count"))
|
data.totalMessages = parseInt(messages.getAttribute("count"))
|
||||||
|
|
||||||
self.userDetails.ping()
|
this.userDetails.ping()
|
||||||
for (const action of self._onLoggedIn) {
|
for (const action of this._onLoggedIn) {
|
||||||
action(self.userDetails.data)
|
action(this.userDetails.data)
|
||||||
}
|
}
|
||||||
self._onLoggedIn = []
|
this._onLoggedIn = []
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -289,11 +297,11 @@ export class OsmConnection {
|
||||||
public async interact(
|
public async interact(
|
||||||
path: string,
|
path: string,
|
||||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||||
header?: Record<string, string | number>,
|
header?: Record<string, string>,
|
||||||
content?: string,
|
content?: string,
|
||||||
allowAnonymous: boolean = false
|
allowAnonymous: boolean = false
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let connection: OSMAuthInstance = this.auth
|
const connection: osmAuth = this.auth
|
||||||
if (allowAnonymous && !this.auth.authenticated()) {
|
if (allowAnonymous && !this.auth.authenticated()) {
|
||||||
const possibleResult = await Utils.downloadAdvanced(
|
const possibleResult = await Utils.downloadAdvanced(
|
||||||
`${this.Backend()}/api/0.6/${path}`,
|
`${this.Backend()}/api/0.6/${path}`,
|
||||||
|
@ -310,15 +318,13 @@ export class OsmConnection {
|
||||||
|
|
||||||
return new Promise((ok, error) => {
|
return new Promise((ok, error) => {
|
||||||
connection.xhr(
|
connection.xhr(
|
||||||
<any>{
|
{
|
||||||
method,
|
method,
|
||||||
options: {
|
headers: header,
|
||||||
header,
|
|
||||||
},
|
|
||||||
content,
|
content,
|
||||||
path: `/api/0.6/${path}`,
|
path: `/api/0.6/${path}`
|
||||||
},
|
},
|
||||||
function (err, response) {
|
function(err, response) {
|
||||||
if (err !== null) {
|
if (err !== null) {
|
||||||
error(err)
|
error(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -329,32 +335,32 @@ export class OsmConnection {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async post(
|
public async post<T extends string>(
|
||||||
path: string,
|
path: string,
|
||||||
content?: string,
|
content?: string,
|
||||||
header?: Record<string, string | number>,
|
header?: Record<string, string>,
|
||||||
allowAnonymous: boolean = false
|
allowAnonymous: boolean = false
|
||||||
): Promise<any> {
|
): Promise<T> {
|
||||||
return await this.interact(path, "POST", header, content, allowAnonymous)
|
return <T> await this.interact(path, "POST", header, content, allowAnonymous)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async put(
|
public async put<T extends string>(
|
||||||
path: string,
|
path: string,
|
||||||
content?: string,
|
content?: string,
|
||||||
header?: Record<string, string | number>
|
header?: Record<string, string>
|
||||||
): Promise<any> {
|
): Promise<T> {
|
||||||
return await this.interact(path, "PUT", header, content)
|
return <T> await this.interact(path, "PUT", header, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get(
|
public async get(
|
||||||
path: string,
|
path: string,
|
||||||
header?: Record<string, string | number>,
|
header?: Record<string, string>,
|
||||||
allowAnonymous: boolean = false
|
allowAnonymous: boolean = false
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return await this.interact(path, "GET", header, undefined, allowAnonymous)
|
return await this.interact(path, "GET", header, undefined, allowAnonymous)
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeNote(id: number | string, text?: string): Promise<void> {
|
public closeNote(id: number | string, text?: string): Promise<string> {
|
||||||
let textSuffix = ""
|
let textSuffix = ""
|
||||||
if ((text ?? "") !== "") {
|
if ((text ?? "") !== "") {
|
||||||
textSuffix = "?text=" + encodeURIComponent(text)
|
textSuffix = "?text=" + encodeURIComponent(text)
|
||||||
|
@ -362,17 +368,17 @@ export class OsmConnection {
|
||||||
if (this._dryRun.data) {
|
if (this._dryRun.data) {
|
||||||
console.warn("Dryrun enabled - not actually closing note ", id, " with text ", text)
|
console.warn("Dryrun enabled - not actually closing note ", id, " with text ", text)
|
||||||
return new Promise((ok) => {
|
return new Promise((ok) => {
|
||||||
ok()
|
ok("")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.post(`notes/${id}/close${textSuffix}`)
|
return this.post(`notes/${id}/close${textSuffix}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
public reopenNote(id: number | string, text?: string): Promise<void> {
|
public reopenNote(id: number | string, text?: string): Promise<string> {
|
||||||
if (this._dryRun.data) {
|
if (this._dryRun.data) {
|
||||||
console.warn("Dryrun enabled - not actually reopening note ", id, " with text ", text)
|
console.warn("Dryrun enabled - not actually reopening note ", id, " with text ", text)
|
||||||
return new Promise((ok) => {
|
return new Promise(resolve => {
|
||||||
ok()
|
resolve("")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let textSuffix = ""
|
let textSuffix = ""
|
||||||
|
@ -398,7 +404,7 @@ export class OsmConnection {
|
||||||
"notes.json",
|
"notes.json",
|
||||||
content,
|
content,
|
||||||
{
|
{
|
||||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
@ -439,7 +445,7 @@ export class OsmConnection {
|
||||||
file: gpx,
|
file: gpx,
|
||||||
description: options.description,
|
description: options.description,
|
||||||
tags: options.labels?.join(",") ?? "",
|
tags: options.labels?.join(",") ?? "",
|
||||||
visibility: options.visibility,
|
visibility: options.visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!contents.description) {
|
if (!contents.description) {
|
||||||
|
@ -447,9 +453,9 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
const extras = {
|
const extras = {
|
||||||
file:
|
file:
|
||||||
'; filename="' +
|
"; filename=\"" +
|
||||||
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
||||||
'"\r\nContent-Type: application/gpx+xml',
|
"\"\r\nContent-Type: application/gpx+xml"
|
||||||
}
|
}
|
||||||
|
|
||||||
const boundary = "987654"
|
const boundary = "987654"
|
||||||
|
@ -457,7 +463,7 @@ export class OsmConnection {
|
||||||
let body = ""
|
let body = ""
|
||||||
for (const key in contents) {
|
for (const key in contents) {
|
||||||
body += "--" + boundary + "\r\n"
|
body += "--" + boundary + "\r\n"
|
||||||
body += 'Content-Disposition: form-data; name="' + key + '"'
|
body += "Content-Disposition: form-data; name=\"" + key + "\""
|
||||||
if (extras[key] !== undefined) {
|
if (extras[key] !== undefined) {
|
||||||
body += extras[key]
|
body += extras[key]
|
||||||
}
|
}
|
||||||
|
@ -468,7 +474,7 @@ export class OsmConnection {
|
||||||
|
|
||||||
const response = await this.post("gpx/create", body, {
|
const response = await this.post("gpx/create", body, {
|
||||||
"Content-Type": "multipart/form-data; boundary=" + boundary,
|
"Content-Type": "multipart/form-data; boundary=" + boundary,
|
||||||
"Content-Length": body.length,
|
"Content-Length": ""+body.length
|
||||||
})
|
})
|
||||||
const parsed = JSON.parse(response)
|
const parsed = JSON.parse(response)
|
||||||
console.log("Uploaded GPX track", parsed)
|
console.log("Uploaded GPX track", parsed)
|
||||||
|
@ -491,9 +497,9 @@ export class OsmConnection {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
||||||
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`,
|
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`
|
||||||
},
|
},
|
||||||
function (err, _) {
|
function(err) {
|
||||||
if (err !== null) {
|
if (err !== null) {
|
||||||
error(err)
|
error(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -508,7 +514,7 @@ export class OsmConnection {
|
||||||
* To be called by land.html
|
* To be called by land.html
|
||||||
*/
|
*/
|
||||||
public finishLogin(callback: (previousURL: string) => void) {
|
public finishLogin(callback: (previousURL: string) => void) {
|
||||||
this.auth.authenticate(function () {
|
this.auth.authenticate(function() {
|
||||||
// Fully authed at this point
|
// Fully authed at this point
|
||||||
console.log("Authentication successful!")
|
console.log("Authentication successful!")
|
||||||
const previousLocation = LocalStorageSource.Get("location_before_login")
|
const previousLocation = LocalStorageSource.Get("location_before_login")
|
||||||
|
@ -517,28 +523,6 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateAuthObject() {
|
private updateAuthObject() {
|
||||||
let pwaStandAloneMode = false
|
|
||||||
try {
|
|
||||||
if (Utils.runningFromConsole) {
|
|
||||||
pwaStandAloneMode = true
|
|
||||||
} else if (
|
|
||||||
window.matchMedia("(display-mode: standalone)").matches ||
|
|
||||||
window.matchMedia("(display-mode: fullscreen)").matches
|
|
||||||
) {
|
|
||||||
pwaStandAloneMode = true
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(
|
|
||||||
"Detecting standalone mode failed",
|
|
||||||
e,
|
|
||||||
". Assuming in browser and not worrying furhter"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const standalone = this._iframeMode || pwaStandAloneMode || !this._singlePage
|
|
||||||
|
|
||||||
// In standalone mode, we DON'T use single page login, as 'redirecting' opens a new window anyway...
|
|
||||||
// Same for an iframe...
|
|
||||||
|
|
||||||
this.auth = new osmAuth({
|
this.auth = new osmAuth({
|
||||||
client_id: this._oauth_config.oauth_client_id,
|
client_id: this._oauth_config.oauth_client_id,
|
||||||
url: this._oauth_config.url,
|
url: this._oauth_config.url,
|
||||||
|
@ -546,23 +530,22 @@ export class OsmConnection {
|
||||||
redirect_uri: Utils.runningFromConsole
|
redirect_uri: Utils.runningFromConsole
|
||||||
? "https://mapcomplete.org/land.html"
|
? "https://mapcomplete.org/land.html"
|
||||||
: window.location.protocol + "//" + window.location.host + "/land.html",
|
: window.location.protocol + "//" + window.location.host + "/land.html",
|
||||||
singlepage: true,
|
singlepage: true, // We always use 'singlePage', it is the most stable - including in PWA
|
||||||
auto: true,
|
auto: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private CheckForMessagesContinuously() {
|
private CheckForMessagesContinuously() {
|
||||||
const self = this
|
|
||||||
if (this.isChecking) {
|
if (this.isChecking) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Stores.Chronic(3 * 1000).addCallback((_) => {
|
Stores.Chronic(3 * 1000).addCallback(() => {
|
||||||
if (!(self.apiIsOnline.data === "unreachable" || self.apiIsOnline.data === "offline")) {
|
if (!(this.apiIsOnline.data === "unreachable" || this.apiIsOnline.data === "offline")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
console.log("Api is offline - trying to reconnect...")
|
console.log("Api is offline - trying to reconnect...")
|
||||||
self.AttemptLogin()
|
this.AttemptLogin()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not login due to", e)
|
console.log("Could not login due to", e)
|
||||||
}
|
}
|
||||||
|
@ -571,10 +554,10 @@ export class OsmConnection {
|
||||||
if (!this._doCheckRegularly) {
|
if (!this._doCheckRegularly) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Stores.Chronic(60 * 5 * 1000).addCallback((_) => {
|
Stores.Chronic(60 * 5 * 1000).addCallback(() => {
|
||||||
if (self.isLoggedIn.data) {
|
if (this.isLoggedIn.data) {
|
||||||
try {
|
try {
|
||||||
self.AttemptLogin()
|
this.AttemptLogin()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not login due to", e)
|
console.log("Could not login due to", e)
|
||||||
}
|
}
|
||||||
|
@ -592,19 +575,9 @@ export class OsmConnection {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly _userInfoCache: Record<number, any> = {}
|
private readonly _userInfoCache: Record<number, OsmUserInfo> = {}
|
||||||
|
|
||||||
public async getInformationAboutUser(id: number): Promise<{
|
public async getInformationAboutUser(id: number): Promise<OsmUserInfo> {
|
||||||
id: number
|
|
||||||
display_name: string
|
|
||||||
account_created: string
|
|
||||||
description: string
|
|
||||||
contributor_terms: { agreed: boolean }
|
|
||||||
roles: []
|
|
||||||
changesets: { count: number }
|
|
||||||
traces: { count: number }
|
|
||||||
blocks: { received: { count: number; active: number } }
|
|
||||||
}> {
|
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ export default class UserRelatedState {
|
||||||
public readonly fixateNorth: UIEventSource<undefined | "yes">
|
public readonly fixateNorth: UIEventSource<undefined | "yes">
|
||||||
public readonly a11y: UIEventSource<undefined | "always" | "never" | "default">
|
public readonly a11y: UIEventSource<undefined | "always" | "never" | "default">
|
||||||
public readonly homeLocation: FeatureSource
|
public readonly homeLocation: FeatureSource
|
||||||
|
public readonly morePrivacy: UIEventSource<undefined | "yes" | "no">
|
||||||
/**
|
/**
|
||||||
* The language as saved into the preferences of the user, if logged in.
|
* The language as saved into the preferences of the user, if logged in.
|
||||||
* Note that this is _different_ from the languages a user can set via the osm.org interface here: https://www.openstreetmap.org/preferences
|
* Note that this is _different_ from the languages a user can set via the osm.org interface here: https://www.openstreetmap.org/preferences
|
||||||
|
@ -106,12 +107,12 @@ export default class UserRelatedState {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
this.language = this.osmConnection.GetPreference("language")
|
this.language = this.osmConnection.GetPreference("language")
|
||||||
this.showTags = <UIEventSource<any>>this.osmConnection.GetPreference("show_tags")
|
this.showTags = this.osmConnection.GetPreference("show_tags")
|
||||||
this.showCrosshair = <UIEventSource<any>>this.osmConnection.GetPreference("show_crosshair")
|
this.showCrosshair = this.osmConnection.GetPreference("show_crosshair")
|
||||||
this.fixateNorth = <UIEventSource<"yes">>this.osmConnection.GetPreference("fixate-north")
|
this.fixateNorth = this.osmConnection.GetPreference("fixate-north")
|
||||||
this.a11y = <UIEventSource<"always" | "never" | "default">>(
|
this.morePrivacy = this.osmConnection.GetPreference("more_privacy", "no")
|
||||||
this.osmConnection.GetPreference("a11y")
|
|
||||||
)
|
this.a11y = this.osmConnection.GetPreference("a11y")
|
||||||
|
|
||||||
this.mangroveIdentity = new MangroveIdentity(
|
this.mangroveIdentity = new MangroveIdentity(
|
||||||
this.osmConnection.GetLongPreference("identity", "mangrove"),
|
this.osmConnection.GetLongPreference("identity", "mangrove"),
|
||||||
|
|
|
@ -564,5 +564,5 @@ export interface LayerConfigJson {
|
||||||
* ifunset: Write 'change_within_x_m' as usual and if GPS is enabled
|
* ifunset: Write 'change_within_x_m' as usual and if GPS is enabled
|
||||||
* iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey
|
* iftrue: Do not write 'change_within_x_m' and do not indicate that this was done by survey
|
||||||
*/
|
*/
|
||||||
enableMorePrivacy: boolean
|
enableMorePrivacy?: boolean
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue