forked from MapComplete/MapComplete
Android: get login working
This commit is contained in:
parent
00c233a2eb
commit
88c76498b6
16 changed files with 199 additions and 171 deletions
2
android
2
android
|
@ -1 +1 @@
|
|||
Subproject commit b165ec6005cb5e9fcc7c1c2bb860344287f3d281
|
||||
Subproject commit 917fe6a0f9ef67530f281d5603432f9c8daae0c7
|
|
@ -3,6 +3,7 @@
|
|||
<head><title>MapComplete Auth</title></head>
|
||||
<body>
|
||||
Authorizing and redirecting, hang on...
|
||||
<div id="token"></div>
|
||||
<script type="module" src="./land.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
10
app/land.ts
10
app/land.ts
|
@ -1,11 +1,17 @@
|
|||
import { OsmConnection } from "../src/Logic/Osm/OsmConnection"
|
||||
import Constants from "../src/Models/Constants"
|
||||
import { Utils } from "../src/Utils"
|
||||
import { UIEventSource } from "../src/Logic/UIEventSource"
|
||||
import { VariableUiElement } from "../src/UI/Base/VariableUIElement"
|
||||
|
||||
console.log("Authorizing...")
|
||||
const key = Constants.osmAuthConfig.url + "oauth2_state"
|
||||
const st =window.localStorage.getItem(key )
|
||||
console.log("Prev state is",key, st)
|
||||
new OsmConnection().finishLogin((_, token: string) => {
|
||||
console.log("Login finished, redirecting to passthrough")
|
||||
const tokenSrc = new UIEventSource("")
|
||||
new VariableUiElement(tokenSrc).AttachTo("token")
|
||||
new OsmConnection().finishLogin(async (_, token: string) => {
|
||||
console.log("Login finished, redirecting to passthrough; token is "+token)
|
||||
await Utils.waitFor(10)
|
||||
window.location.href = "https://app.mapcomplete.org/passthrough.html?oauth_token="+token
|
||||
})
|
||||
|
|
|
@ -49,6 +49,7 @@ cp -r dist/assets/templates dist-full/assets
|
|||
cp -r dist/assets/themes dist-full/assets
|
||||
|
||||
# mkdir dist-full/assets/generated
|
||||
nvm use
|
||||
|
||||
# assets/icon-only.png will be used as the app icon
|
||||
# See https://capacitorjs.com/docs/guides/splash-screens-and-icons
|
||||
|
@ -56,4 +57,4 @@ npx capacitor-assets generate
|
|||
|
||||
npx cap sync
|
||||
|
||||
echo "All done! Don't forget to click 'gradly sync files' in Android Studio"
|
||||
echo "All done! Don't forget to click 'gradle sync files' in Android Studio"
|
||||
|
|
|
@ -6,6 +6,7 @@ import Constants from "../../Models/Constants"
|
|||
import { Changes } from "./Changes"
|
||||
import { Utils } from "../../Utils"
|
||||
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||
|
||||
export interface ChangesetTag {
|
||||
key: string
|
||||
|
@ -52,7 +53,7 @@ export class ChangesetHandler {
|
|||
| { addAlias: (id0: string, id1: string) => void }
|
||||
| undefined,
|
||||
changes: Changes,
|
||||
reportError: (e: string | Error, extramessage: string) => void
|
||||
reportError: (e: string | Error, extramessage: string) => void,
|
||||
) {
|
||||
this.osmConnection = osmConnection
|
||||
this._reportError = reportError
|
||||
|
@ -113,7 +114,7 @@ export class ChangesetHandler {
|
|||
private async UploadWithNew(
|
||||
generateChangeXML: (csid: number, remappings: Map<string, string>) => string,
|
||||
openChangeset: UIEventSource<number>,
|
||||
extraMetaTags: ChangesetTag[]
|
||||
extraMetaTags: ChangesetTag[],
|
||||
) {
|
||||
const csId = await this.OpenChangeset(extraMetaTags)
|
||||
openChangeset.setData(csId)
|
||||
|
@ -121,7 +122,7 @@ export class ChangesetHandler {
|
|||
console.log(
|
||||
"Opened a new changeset (openChangeset.data is undefined):",
|
||||
changeset,
|
||||
extraMetaTags
|
||||
extraMetaTags,
|
||||
)
|
||||
const changes = await this.UploadChange(csId, changeset)
|
||||
const hasSpecialMotivationChanges = ChangesetHandler.rewriteMetaTags(extraMetaTags, changes)
|
||||
|
@ -144,7 +145,7 @@ export class ChangesetHandler {
|
|||
public async UploadChangeset(
|
||||
generateChangeXML: (csid: number, remappings: Map<string, string>) => string,
|
||||
extraMetaTags: ChangesetTag[],
|
||||
openChangeset: UIEventSource<number>
|
||||
openChangeset: UIEventSource<number>,
|
||||
): Promise<void> {
|
||||
if (
|
||||
!extraMetaTags.some((tag) => tag.key === "comment") ||
|
||||
|
@ -179,13 +180,13 @@ export class ChangesetHandler {
|
|||
try {
|
||||
const rewritings = await this.UploadChange(
|
||||
csId,
|
||||
generateChangeXML(csId, this._remappings)
|
||||
generateChangeXML(csId, this._remappings),
|
||||
)
|
||||
|
||||
const rewrittenTags = this.RewriteTagsOf(
|
||||
extraMetaTags,
|
||||
rewritings,
|
||||
oldChangesetMeta
|
||||
oldChangesetMeta,
|
||||
)
|
||||
await this.UpdateTags(csId, rewrittenTags)
|
||||
return // We are done!
|
||||
|
@ -196,7 +197,7 @@ export class ChangesetHandler {
|
|||
} catch (e) {
|
||||
this._reportError(
|
||||
e,
|
||||
"While getting metadata from a changeset " + openChangeset.data
|
||||
"While getting metadata from a changeset " + openChangeset.data,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +225,7 @@ export class ChangesetHandler {
|
|||
console.warn(
|
||||
"Could not open/upload changeset due to ",
|
||||
e,
|
||||
"trying again with a another fresh changeset "
|
||||
"trying again with a another fresh changeset ",
|
||||
)
|
||||
openChangeset.setData(undefined)
|
||||
|
||||
|
@ -250,7 +251,7 @@ export class ChangesetHandler {
|
|||
uid: number // User ID
|
||||
changes_count: number
|
||||
tags: any
|
||||
}
|
||||
},
|
||||
): ChangesetTag[] {
|
||||
// Note: extraMetaTags is where all the tags are collected into
|
||||
|
||||
|
@ -387,7 +388,7 @@ export class ChangesetHandler {
|
|||
tag.key !== undefined &&
|
||||
tag.value !== undefined &&
|
||||
tag.key !== "" &&
|
||||
tag.value !== ""
|
||||
tag.value !== "",
|
||||
)
|
||||
const metadata = tags.map((kv) => `<tag k="${kv.key}" v="${escapeHtml(kv.value)}"/>`)
|
||||
const content = [`<osm><changeset>`, metadata, `</changeset></osm>`].join("")
|
||||
|
@ -398,10 +399,16 @@ export class ChangesetHandler {
|
|||
const usedGps = this.changes.state["currentUserLocation"]?.features?.data?.length > 0
|
||||
const hasMorePrivacy = !!this.changes.state?.featureSwitches?.featureSwitchMorePrivacy?.data
|
||||
const setSourceAsSurvey = !hasMorePrivacy && usedGps
|
||||
let shell = ""
|
||||
let host = `${window.location.origin}${window.location.pathname}`
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
shell = " (Android)"
|
||||
host = "https://mapcomplete.org/" + window.location.pathname
|
||||
}
|
||||
return [
|
||||
["created_by", `MapComplete ${Constants.vNumber}`],
|
||||
["created_by", `MapComplete ${Constants.vNumber}${shell}`],
|
||||
["locale", Locale.language.data],
|
||||
["host", `${window.location.origin}${window.location.pathname}`], // Note: deferred changes might give a different hostpath then the theme with which the changes were made
|
||||
["host", host], // Note: deferred changes might give a different hostpath then the theme with which the changes were made
|
||||
["source", setSourceAsSurvey ? "survey" : undefined],
|
||||
["imagery", this.changes.state["backgroundLayer"]?.data?.id],
|
||||
].map(([key, value]) => ({
|
||||
|
@ -427,7 +434,7 @@ export class ChangesetHandler {
|
|||
const csId = await this.osmConnection.put(
|
||||
"changeset/create",
|
||||
[`<osm><changeset>`, metadata, `</changeset></osm>`].join(""),
|
||||
{ "Content-Type": "text/xml" }
|
||||
{ "Content-Type": "text/xml" },
|
||||
)
|
||||
return Number(csId)
|
||||
}
|
||||
|
@ -437,12 +444,12 @@ export class ChangesetHandler {
|
|||
*/
|
||||
private async UploadChange(
|
||||
changesetId: number,
|
||||
changesetXML: string
|
||||
changesetXML: string,
|
||||
): Promise<Map<string, string>> {
|
||||
const response = await this.osmConnection.post<XMLDocument>(
|
||||
"changeset/" + changesetId + "/upload",
|
||||
changesetXML,
|
||||
{ "Content-Type": "text/xml" }
|
||||
{ "Content-Type": "text/xml" },
|
||||
)
|
||||
const changes = this.parseUploadChangesetResponse(response)
|
||||
console.log("Uploaded changeset ", changesetId)
|
||||
|
|
|
@ -5,41 +5,70 @@ import { Utils } from "../../Utils"
|
|||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { AuthConfig } from "./AuthConfig"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||
import { Feature, Point } from "geojson"
|
||||
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
|
||||
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 {
|
||||
public loggedIn = false
|
||||
public name = "Not logged in"
|
||||
public uid: number
|
||||
public csCount = 0
|
||||
public img?: string
|
||||
public unreadMessages = 0
|
||||
public totalMessages: number = 0
|
||||
public home: { lon: number; lat: number }
|
||||
public backend: string
|
||||
public account_created: string
|
||||
public tracesCount: number = 0
|
||||
public description: string
|
||||
public languages: string[]
|
||||
|
||||
constructor(backend: string) {
|
||||
this.backend = backend
|
||||
"id": number,
|
||||
"display_name": string,
|
||||
"account_created": string,
|
||||
"description": string,
|
||||
"contributor_terms": {
|
||||
"agreed": boolean,
|
||||
"pd": boolean
|
||||
},
|
||||
"img": {
|
||||
"href": string,
|
||||
},
|
||||
"roles": string[],
|
||||
"changesets": {
|
||||
"count": number
|
||||
},
|
||||
"traces": {
|
||||
"count": number
|
||||
},
|
||||
"blocks": {
|
||||
"received": {
|
||||
"count": number,
|
||||
"active": number
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"lat": number,
|
||||
"lon": number,
|
||||
"zoom": number
|
||||
},
|
||||
"languages": string[],
|
||||
"messages": {
|
||||
"received": {
|
||||
"count": number,
|
||||
"unread": number
|
||||
},
|
||||
"sent": {
|
||||
"count": number
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default interface UserDetails {
|
||||
loggedIn: boolean
|
||||
name: string
|
||||
uid: number
|
||||
csCount: number
|
||||
img?: string
|
||||
unreadMessages: number
|
||||
totalMessages: number
|
||||
home?: { lon: number; lat: number }
|
||||
backend: string
|
||||
account_created: string
|
||||
tracesCount: number
|
||||
description?: string
|
||||
languages: string[]
|
||||
|
||||
}
|
||||
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
||||
|
||||
interface CapabilityResult {
|
||||
|
@ -77,7 +106,10 @@ interface CapabilityResult {
|
|||
|
||||
export class OsmConnection {
|
||||
public auth: osmAuth
|
||||
public userDetails: UIEventSource<UserDetails>
|
||||
/**
|
||||
* Details of the currently logged-in user; undefined if not logged in
|
||||
*/
|
||||
public userDetails: UIEventSource<UserDetails | undefined>
|
||||
public isLoggedIn: Store<boolean>
|
||||
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||
"unknown",
|
||||
|
@ -93,7 +125,6 @@ export class OsmConnection {
|
|||
public readonly _oauth_config: AuthConfig
|
||||
private readonly _dryRun: Store<boolean>
|
||||
private readonly fakeUser: boolean
|
||||
private _onLoggedIn: ((userDetails: UserDetails) => void)[] = []
|
||||
private readonly _iframeMode: boolean
|
||||
private readonly _singlePage: boolean
|
||||
private isChecking = false
|
||||
|
@ -129,10 +160,7 @@ export class OsmConnection {
|
|||
this._oauth_config.oauth_secret = import.meta.env.VITE_OSM_OAUTH_SECRET
|
||||
}
|
||||
|
||||
this.userDetails = new UIEventSource<UserDetails>(
|
||||
new UserDetails(this._oauth_config.url),
|
||||
"userDetails",
|
||||
)
|
||||
this.userDetails = new UIEventSource<UserDetails>(undefined, "userDetails")
|
||||
if (options.fakeUser) {
|
||||
const ud = this.userDetails.data
|
||||
ud.csCount = 5678
|
||||
|
@ -146,25 +174,21 @@ export class OsmConnection {
|
|||
"The 'fake-user' is a URL-parameter which allows to test features without needing an OSM account or even internet connection."
|
||||
this.loadingStatus.setData("logged-in")
|
||||
}
|
||||
this.UpdateCapabilities()
|
||||
this.updateCapabilities()
|
||||
|
||||
this.isLoggedIn = this.userDetails.map(
|
||||
(user) =>
|
||||
user.loggedIn &&
|
||||
!!user &&
|
||||
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
||||
[this.apiIsOnline],
|
||||
)
|
||||
this.isLoggedIn.addCallback((isLoggedIn) => {
|
||||
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
|
||||
// This means someone attempted to toggle this; so we attempt to login!
|
||||
this.AttemptLogin()
|
||||
}
|
||||
})
|
||||
|
||||
this._dryRun = options.dryRun ?? new UIEventSource<boolean>(false)
|
||||
|
||||
this.updateAuthObject()
|
||||
this.createAuthObject()
|
||||
AndroidPolyfill.inAndroid.addCallback(() => {
|
||||
this.createAuthObject()
|
||||
})
|
||||
if (!this.fakeUser) {
|
||||
this.CheckForMessagesContinuously()
|
||||
}
|
||||
|
@ -209,9 +233,6 @@ export class OsmConnection {
|
|||
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
||||
}
|
||||
|
||||
public OnLoggedIn(action: (userDetails: UserDetails) => void) {
|
||||
this._onLoggedIn.push(action)
|
||||
}
|
||||
|
||||
public LogOut() {
|
||||
this.auth.logout()
|
||||
|
@ -233,7 +254,7 @@ export class OsmConnection {
|
|||
}
|
||||
|
||||
public AttemptLogin() {
|
||||
this.UpdateCapabilities()
|
||||
this.updateCapabilities()
|
||||
if (this.loadingStatus.data !== "logged-in") {
|
||||
// Stay 'logged-in' if we are already logged in; this simply means we are checking for messages
|
||||
this.loadingStatus.setData("loading")
|
||||
|
@ -245,87 +266,63 @@ export class OsmConnection {
|
|||
}
|
||||
|
||||
console.log("Trying to log in...")
|
||||
this.updateAuthObject()
|
||||
|
||||
LocalStorageSource.get("location_before_login").setData(
|
||||
Utils.runningFromConsole ? undefined : window.location.href,
|
||||
)
|
||||
this.auth.xhr(
|
||||
{
|
||||
method: "GET",
|
||||
path: "/api/0.6/user/details",
|
||||
},
|
||||
(err, details: XMLDocument) => {
|
||||
if (err != null) {
|
||||
console.log("Could not login due to:", err)
|
||||
this.loadingStatus.setData("error")
|
||||
if (err.status == 401) {
|
||||
console.log("Clearing tokens...")
|
||||
// Not authorized - our token probably got revoked
|
||||
this.auth.logout()
|
||||
this.LogOut()
|
||||
} else {
|
||||
console.log("Other error. Status:", err.status)
|
||||
this.apiIsOnline.setData("unreachable")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (details == null) {
|
||||
this.loadingStatus.setData("error")
|
||||
return
|
||||
}
|
||||
this.auth.authenticate((err, result) => {
|
||||
if (!err) {
|
||||
this.loadUserInfo()
|
||||
}
|
||||
})
|
||||
|
||||
// details is an XML DOM of user details
|
||||
const userInfo = details.getElementsByTagName("user")[0]
|
||||
}
|
||||
|
||||
const data = this.userDetails.data
|
||||
data.loggedIn = true
|
||||
console.log("Login completed, userinfo is ", userInfo)
|
||||
data.name = userInfo.getAttribute("display_name")
|
||||
data.account_created = userInfo.getAttribute("account_created")
|
||||
data.uid = Number(userInfo.getAttribute("id"))
|
||||
data.languages = Array.from(
|
||||
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang"),
|
||||
).map((l) => l.textContent)
|
||||
data.csCount = Number.parseInt(
|
||||
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0",
|
||||
)
|
||||
data.tracesCount = Number.parseInt(
|
||||
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0",
|
||||
)
|
||||
private async loadUserInfo() {
|
||||
try {
|
||||
const result = await this.interact("user/details.json")
|
||||
if (result === null) {
|
||||
this.loadingStatus.setData("error")
|
||||
return
|
||||
}
|
||||
const data = <{
|
||||
"version": "0.6",
|
||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||
"user": OsmUserInfo
|
||||
}>JSON.parse(result)
|
||||
const user = data.user
|
||||
const userdetails: UserDetails = {
|
||||
uid: user.id,
|
||||
name: user.display_name,
|
||||
csCount: user.changesets.count,
|
||||
description: user.description,
|
||||
loggedIn: true,
|
||||
backend: this.Backend(),
|
||||
home: user.home,
|
||||
languages: user.languages,
|
||||
totalMessages: user.messages.received?.count ?? 0,
|
||||
img: user.img?.href,
|
||||
account_created: user.account_created,
|
||||
tracesCount: user.traces.count,
|
||||
unreadMessages: user.messages.received?.unread ?? 0,
|
||||
}
|
||||
console.log("Login completed, userinfo is ", userdetails)
|
||||
this.userDetails.set(userdetails)
|
||||
this.loadingStatus.setData("logged-in")
|
||||
|
||||
data.img = undefined
|
||||
const imgEl = userInfo.getElementsByTagName("img")
|
||||
if (imgEl !== undefined && imgEl[0] !== undefined) {
|
||||
data.img = imgEl[0].getAttribute("href")
|
||||
}
|
||||
|
||||
const description = userInfo.getElementsByTagName("description")
|
||||
if (description !== undefined && description[0] !== undefined) {
|
||||
data.description = description[0]?.innerHTML
|
||||
}
|
||||
const homeEl = userInfo.getElementsByTagName("home")
|
||||
if (homeEl !== undefined && homeEl[0] !== undefined) {
|
||||
const lat = parseFloat(homeEl[0].getAttribute("lat"))
|
||||
const lon = parseFloat(homeEl[0].getAttribute("lon"))
|
||||
data.home = { lat: lat, lon: lon }
|
||||
}
|
||||
|
||||
this.loadingStatus.setData("logged-in")
|
||||
const messages = userInfo
|
||||
.getElementsByTagName("messages")[0]
|
||||
.getElementsByTagName("received")[0]
|
||||
data.unreadMessages = parseInt(messages.getAttribute("unread"))
|
||||
data.totalMessages = parseInt(messages.getAttribute("count"))
|
||||
|
||||
this.userDetails.ping()
|
||||
for (const action of this._onLoggedIn) {
|
||||
action(this.userDetails.data)
|
||||
}
|
||||
this._onLoggedIn = []
|
||||
},
|
||||
)
|
||||
} catch (err) {
|
||||
console.log("Could not login due to:", err)
|
||||
this.loadingStatus.setData("error")
|
||||
if (err.status == 401) {
|
||||
console.log("Clearing tokens...")
|
||||
// Not authorized - our token probably got revoked
|
||||
this.auth.logout()
|
||||
this.LogOut()
|
||||
} else {
|
||||
console.log("Other error. Status:", err.status)
|
||||
this.apiIsOnline.setData("unreachable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,7 +336,7 @@ export class OsmConnection {
|
|||
*/
|
||||
public async interact(
|
||||
path: string,
|
||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
method: "GET" | "POST" | "PUT" | "DELETE" = "GET",
|
||||
header?: Record<string, string>,
|
||||
content?: string,
|
||||
allowAnonymous: boolean = false,
|
||||
|
@ -359,6 +356,11 @@ export class OsmConnection {
|
|||
throw "Could not interact with OSM:" + possibleResult["error"]
|
||||
}
|
||||
|
||||
if (!this.auth.authenticated()) {
|
||||
console.trace("Not authenticated")
|
||||
await Utils.waitFor(10000)
|
||||
}
|
||||
|
||||
return new Promise((ok, error) => {
|
||||
connection.xhr(
|
||||
{
|
||||
|
@ -504,7 +506,7 @@ export class OsmConnection {
|
|||
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
||||
"\"\r\nContent-Type: application/gpx+xml",
|
||||
}
|
||||
user
|
||||
|
||||
const boundary = "987654"
|
||||
|
||||
let body = ""
|
||||
|
@ -563,19 +565,29 @@ export class OsmConnection {
|
|||
this.auth.authenticate(() => {
|
||||
// Fully authed at this point
|
||||
console.log("Authentication successful!")
|
||||
const oauth_token = window.localStorage.getItem(this._oauth_config.url + "oauth2_access_token")
|
||||
const oauth_token = QueryParameters.GetQueryParameter("oauth_token", undefined).data ?? window.localStorage.getItem(this._oauth_config.url + "oauth2_access_token")
|
||||
const previousLocation = LocalStorageSource.get("location_before_login")
|
||||
callback(previousLocation.data, oauth_token)
|
||||
})
|
||||
}
|
||||
|
||||
private updateAuthObject() {
|
||||
private async loginAndroidPolyfill() {
|
||||
const token = await AndroidPolyfill.requestLoginCodes()
|
||||
console.log("Got login token!", token)
|
||||
localStorage.setItem("https://www.openstreetmap.orgoauth2_access_token", token)
|
||||
if (this.auth.authenticated()) {
|
||||
console.log("Logged in!")
|
||||
}
|
||||
await this.loadUserInfo()
|
||||
|
||||
}
|
||||
|
||||
private createAuthObject() {
|
||||
let redirect_uri = Utils.runningFromConsole
|
||||
? "https://mapcomplete.org/land.html"
|
||||
: window.location.protocol + "//" + window.location.host + "/land.html"
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
redirect_uri = "https://app.mapcomplete.org/land.html"
|
||||
AndroidPolyfill.requestLoginCodes(this)
|
||||
}
|
||||
this.auth = new osmAuth({
|
||||
client_id: this._oauth_config.oauth_client_id,
|
||||
|
@ -586,9 +598,12 @@ export class OsmConnection {
|
|||
* However, this breaks in iframes so we open a popup in that case
|
||||
*/
|
||||
singlepage: !this._iframeMode && !AndroidPolyfill.inAndroid.data,
|
||||
auto: true,
|
||||
auto: false,
|
||||
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
|
||||
})
|
||||
if (AndroidPolyfill.inAndroid.data) {
|
||||
this.loginAndroidPolyfill() // NO AWAIT!
|
||||
}
|
||||
}
|
||||
|
||||
private CheckForMessagesContinuously() {
|
||||
|
@ -611,9 +626,10 @@ export class OsmConnection {
|
|||
return
|
||||
}
|
||||
Stores.Chronic(60 * 5 * 1000).addCallback(() => {
|
||||
// Check for new messages every 5 minutes
|
||||
if (this.isLoggedIn.data) {
|
||||
try {
|
||||
this.AttemptLogin()
|
||||
this.loadUserInfo()
|
||||
} catch (e) {
|
||||
console.log("Could not login due to", e)
|
||||
}
|
||||
|
@ -621,11 +637,11 @@ export class OsmConnection {
|
|||
})
|
||||
}
|
||||
|
||||
private UpdateCapabilities(): void {
|
||||
private updateCapabilities(): void {
|
||||
if (this.fakeUser) {
|
||||
return
|
||||
}
|
||||
this.FetchCapabilities().then(({ api, gpx }) => {
|
||||
this.fetchCapabilities().then(({ api, gpx }) => {
|
||||
this.apiIsOnline.setData(api)
|
||||
this.gpxServiceIsOnline.setData(gpx)
|
||||
})
|
||||
|
@ -646,7 +662,8 @@ export class OsmConnection {
|
|||
return parsed
|
||||
}
|
||||
|
||||
private async FetchCapabilities(): Promise<{
|
||||
/**Does not use the OSM-auth object*/
|
||||
private async fetchCapabilities(): Promise<{
|
||||
api: OsmServiceState
|
||||
gpx: OsmServiceState
|
||||
database: OsmServiceState
|
||||
|
@ -656,7 +673,7 @@ export class OsmConnection {
|
|||
}
|
||||
try {
|
||||
const result = await Utils.downloadJson<CapabilityResult>(
|
||||
this.Backend() + "/api/0.6/capabilities.json"
|
||||
this.Backend() + "/api/0.6/capabilities.json",
|
||||
)
|
||||
if (result?.api?.status === undefined) {
|
||||
console.log("Something went wrong:", result)
|
||||
|
|
|
@ -32,7 +32,7 @@ export class OsmPreferences {
|
|||
this.auth = auth
|
||||
this._fakeUser = fakeUser
|
||||
this.osmConnection = osmConnection
|
||||
osmConnection.OnLoggedIn(() => {
|
||||
osmConnection.userDetails.addCallbackAndRunD(() => {
|
||||
this.loadBulkPreferences()
|
||||
return true
|
||||
})
|
||||
|
|
|
@ -7,6 +7,7 @@ import themeOverview from "../../assets/generated/theme_overview.json"
|
|||
import LayerSearch from "./LayerSearch"
|
||||
import SearchUtils from "./SearchUtils"
|
||||
import { OsmConnection } from "../Osm/OsmConnection"
|
||||
import { AndroidPolyfill } from "../Web/AndroidPolyfill"
|
||||
|
||||
type ThemeSearchScore = {
|
||||
theme: MinimalThemeInformation
|
||||
|
@ -82,7 +83,7 @@ export default class ThemeSearch {
|
|||
}
|
||||
|
||||
let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
|
||||
if ((location.hostname === "localhost" && !AndroidPolyfill.inAndroid.data) || location.hostname === "127.0.0.1") {
|
||||
linkPrefix = `${path}/theme.html?layout=${layout.id}&`
|
||||
}
|
||||
|
||||
|
|
|
@ -182,9 +182,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
|
|||
|
||||
let testingDefaultValue = false
|
||||
if (
|
||||
!Utils.runningFromConsole &&
|
||||
(location.hostname === "localhost" || location.hostname === "127.0.0.1") &&
|
||||
!Constants.osmAuthConfig.url.startsWith("https://master.apis.dev.openstreetmap.org")
|
||||
!Constants.osmAuthConfig.url.startsWith("https://master.apis.dev.openstreetmap.org") && (location.hostname === "127.0.0.1") && !Utils.runningFromConsole
|
||||
) {
|
||||
testingDefaultValue = true
|
||||
}
|
||||
|
|
|
@ -51,13 +51,11 @@ export class AndroidPolyfill {
|
|||
this.backfillGeolocation(this.databridgePlugin)
|
||||
}
|
||||
|
||||
public static async requestLoginCodes(osmConnection: OsmConnection) {
|
||||
public static async requestLoginCodes() {
|
||||
const result = await DatabridgePluginSingleton.request<{oauth_token: string}>({ key: "request:login" })
|
||||
const token: string = result.value.oauth_token
|
||||
console.log("AndroidPolyfill: received code and state; trying to pass them to the oauth lib",token)
|
||||
const auth = osmConnection.auth.bootstrapToken(token, (err, result) => {
|
||||
console.log("AndroidPolyFill: bootstraptoken returned", JSON.stringify({err, result}))
|
||||
})
|
||||
console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib",token)
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
const tu = Translations.t.general
|
||||
const tr = Translations.t.general.morescreen
|
||||
|
||||
let userLanguages = osmConnection.userDetails.map((ud) => ud.languages)
|
||||
let userLanguages = osmConnection.userDetails.mapD((ud) => ud.languages)
|
||||
let search: UIEventSource<string | undefined> = new UIEventSource<string>("")
|
||||
let searchStable = search.stabilized(100)
|
||||
|
||||
|
@ -58,7 +58,7 @@
|
|||
hiddenThemes.filter(
|
||||
(theme) =>
|
||||
knownIds.indexOf(theme.id) >= 0 ||
|
||||
state.osmConnection.userDetails.data.name === "Pieter Vander Vennet"
|
||||
state.osmConnection.userDetails.data?.name === "Pieter Vander Vennet"
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
josmState.stabilized(15000).addCallbackD(() => josmState.setData(undefined))
|
||||
|
||||
const showButton = state.osmConnection.userDetails.map(
|
||||
(ud) => ud.loggedIn && ud.csCount >= Constants.userJourney.historyLinkVisible
|
||||
(ud) => ud?.csCount >= Constants.userJourney.historyLinkVisible
|
||||
)
|
||||
|
||||
function openJosm() {
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
const imageInfo = await panoramax.imageInfo(image.id)
|
||||
let reporter_email: string = undefined
|
||||
const userdetails = state.userRelatedState.osmConnection.userDetails
|
||||
if (userdetails.data.loggedIn) {
|
||||
if (!userdetails.data) {
|
||||
reporter_email = userdetails.data.name + "@openstreetmap.org"
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ export class DeleteFlowState {
|
|||
if (ud === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (!ud.loggedIn) {
|
||||
if (!this._osmConnection.isLoggedIn.data) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
$: tagsExplanation = tags?.asHumanString(true, false, currentProperties)
|
||||
</script>
|
||||
|
||||
{#if !userDetails || $userDetails.loggedIn}
|
||||
{#if !userDetails}
|
||||
<div class="break-words" style="word-break: break-word">
|
||||
{#if tags === undefined}
|
||||
<slot name="no-tags"><Tr cls="subtle" t={Translations.t.general.noTagsSelected} /></slot>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
||||
import Test from "./UI/Test.svelte"
|
||||
import { OsmConnection } from "./Logic/Osm/OsmConnection"
|
||||
|
||||
new Test({
|
||||
target: document.getElementById("maindiv"),
|
||||
})
|
||||
new OsmConnection().interact("user/details.json").then(r => console.log(">>>", r))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue