2023-11-01 20:54:19 +00:00
|
|
|
"""OSM Authentication."""
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
import json
|
2023-11-01 20:54:19 +00:00
|
|
|
import typing
|
2021-06-16 14:42:04 +01:00
|
|
|
from datetime import datetime
|
2023-11-01 20:54:19 +00:00
|
|
|
from urllib.parse import urlencode
|
2021-06-16 14:42:04 +01:00
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
import flask
|
2023-11-01 20:54:19 +00:00
|
|
|
import lxml.etree
|
2024-06-06 14:43:44 +01:00
|
|
|
import requests
|
|
|
|
from requests_oauthlib import OAuth2Session
|
2021-06-16 14:42:04 +01:00
|
|
|
|
|
|
|
from . import user_agent_headers
|
2023-11-01 20:54:19 +00:00
|
|
|
from .model import User
|
2021-06-16 14:42:04 +01:00
|
|
|
|
|
|
|
osm_api_base = "https://api.openstreetmap.org/api/0.6"
|
2024-06-06 14:43:44 +01:00
|
|
|
scope = ["read_prefs", "write_api"]
|
|
|
|
|
|
|
|
|
|
|
|
def get_session() -> OAuth2Session:
|
|
|
|
"""Get session."""
|
|
|
|
token = flask.session.get("oauth_token")
|
|
|
|
if not token:
|
|
|
|
user = flask.g.user
|
|
|
|
assert user.is_authenticated
|
|
|
|
token = json.loads(user.osm_oauth_token)
|
|
|
|
flask.session["oauth_token"] = token
|
|
|
|
|
|
|
|
callback = flask.url_for("oauth_callback", _external=True)
|
|
|
|
return OAuth2Session(
|
|
|
|
flask.current_app.config["CLIENT_KEY"],
|
|
|
|
redirect_uri=callback,
|
|
|
|
scope=scope,
|
|
|
|
token=token,
|
|
|
|
)
|
2021-06-16 14:42:04 +01:00
|
|
|
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
def api_put_request(path: str, **kwargs: typing.Any) -> requests.Response:
|
|
|
|
"""Send OSM API PUT request."""
|
|
|
|
oauth = get_session()
|
|
|
|
|
2021-06-16 14:42:04 +01:00
|
|
|
return oauth.request(
|
|
|
|
"PUT", osm_api_base + path, headers=user_agent_headers(), **kwargs
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
def api_request(path: str, **params: typing.Any) -> requests.Response:
|
|
|
|
"""Send OSM API request."""
|
2021-06-16 14:42:04 +01:00
|
|
|
url = osm_api_base + path
|
|
|
|
if params:
|
|
|
|
url += "?" + urlencode(params)
|
2024-06-06 14:43:44 +01:00
|
|
|
|
|
|
|
oauth = get_session()
|
2021-06-16 14:42:04 +01:00
|
|
|
return oauth.get(url, timeout=4)
|
|
|
|
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
def parse_iso_date(value: str) -> datetime:
|
|
|
|
"""Parse ISO date."""
|
2021-06-16 14:42:04 +01:00
|
|
|
return datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
|
|
|
|
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
def parse_userinfo_call(xml: bytes) -> dict[str, typing.Any]:
|
|
|
|
"""Parse userinfo call."""
|
2021-06-16 14:42:04 +01:00
|
|
|
root = lxml.etree.fromstring(xml)
|
|
|
|
user = root[0]
|
|
|
|
img = user.find(".//img")
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
account_created_date = user.get("account_created")
|
|
|
|
assert account_created_date
|
|
|
|
account_created = parse_iso_date(account_created_date)
|
2021-06-16 14:42:04 +01:00
|
|
|
|
|
|
|
assert user.tag == "user"
|
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
id_str = user.get("id")
|
|
|
|
assert id_str and isinstance(id_str, str)
|
|
|
|
|
2021-06-16 14:42:04 +01:00
|
|
|
return {
|
|
|
|
"account_created": account_created,
|
2024-06-06 14:43:44 +01:00
|
|
|
"id": int(id_str),
|
2021-06-16 14:42:04 +01:00
|
|
|
"username": user.get("display_name"),
|
|
|
|
"description": user.findtext(".//description"),
|
|
|
|
"img": (img.get("href") if img is not None else None),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-01 20:54:19 +00:00
|
|
|
def get_username() -> str | None:
|
|
|
|
"""Get username of current user."""
|
2024-06-06 14:43:44 +01:00
|
|
|
if "user_id" not in flask.session:
|
2023-11-01 20:54:19 +00:00
|
|
|
return None # not authorized
|
2021-06-16 14:42:04 +01:00
|
|
|
|
2024-06-06 14:43:44 +01:00
|
|
|
user_id = flask.session["user_id"]
|
2021-06-16 14:42:04 +01:00
|
|
|
|
|
|
|
user = User.query.get(user_id)
|
2023-11-01 20:54:19 +00:00
|
|
|
return typing.cast(str, user.username)
|