Skip to content

Commit dc29a65

Browse files
committed
backend: Use planet.osm.org/users_deleted/users_deleted.txt to avoid hammering API
Signed-off-by: Taylor Smock <[email protected]>
1 parent 00a5dda commit dc29a65

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

backend/api/users/resources.py

+27-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from distutils.util import strtobool
22
from typing import Optional
3+
from collections.abc import Generator
34

45
from flask import stream_with_context, Response
56
from flask_restful import Resource, current_app, request
@@ -144,20 +145,35 @@ def get(self):
144145
@token_auth.login_required
145146
def delete(self):
146147
if UserService.is_user_an_admin(token_auth.current_user()):
147-
148-
def delete_users():
149-
for user in User.get_all_users_not_paginated():
150-
# We specifically want to remove users that have deleted their OSM accounts.
151-
if OSMService.is_osm_user_gone(user.id):
152-
data = UserService.delete_user_by_id(
153-
user.id, token_auth.current_user()
154-
).to_primitive()
155-
yield f"\u001e{data}\n"
156-
157148
return Response(
158-
stream_with_context(delete_users()),
149+
stream_with_context(UsersAllAPI._delete_users()),
159150
headers={"Content-Type": "application/json-seq"},
160151
)
152+
return "Unauthorized", 401
153+
154+
@staticmethod
155+
def _delete_users() -> Generator[str, None, None]:
156+
# Updated daily
157+
deleted_users = OSMService.get_deleted_users()
158+
if deleted_users:
159+
last_deleted_user = 0
160+
for user in User.get_all_users_not_paginated(User.id):
161+
while last_deleted_user < user.id:
162+
last_deleted_user = next(deleted_users)
163+
if last_deleted_user == user.id:
164+
data = UserService.delete_user_by_id(
165+
user.id, token_auth.current_user()
166+
).to_primitive()
167+
yield f"\u001e{data}\n"
168+
return
169+
# Fall back to hitting the API (if the OSM API is not the default)
170+
for user in User.get_all_users_not_paginated():
171+
# We specifically want to remove users that have deleted their OSM accounts.
172+
if OSMService.is_osm_user_gone(user.id):
173+
data = UserService.delete_user_by_id(
174+
user.id, token_auth.current_user()
175+
).to_primitive()
176+
yield f"\u001e{data}\n"
161177

162178

163179
class UsersQueriesUsernameAPI(Resource):

backend/models/postgis/user.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,12 @@ def get_all_users(query: UserSearchQuery) -> UserSearchDTO:
182182
return dto
183183

184184
@staticmethod
185-
def get_all_users_not_paginated():
185+
def get_all_users_not_paginated(*order):
186186
"""Get all users in DB"""
187-
return db.session.query(User.id).all()
187+
query = db.session.query(User.id)
188+
if not order:
189+
return query.all()
190+
return query.order_by(*order).all()
188191

189192
@staticmethod
190193
def filter_users(user_filter: str, project_id: int, page: int) -> UserFilterDTO:

backend/services/users/osm_service.py

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import re
2+
from collections.abc import Generator
3+
from typing import Optional
4+
15
import requests
26
from flask import current_app
37

@@ -32,6 +36,32 @@ def is_osm_user_gone(user_id: int) -> bool:
3236

3337
return False
3438

39+
@staticmethod
40+
def get_deleted_users() -> Optional[Generator[int, None, None]]:
41+
"""
42+
Get the list of deleted users from OpenStreetMap.
43+
This only returns users from the https://www.openstreetmap.org instance.
44+
:return: The deleted users
45+
"""
46+
if current_app.config["OSM_SERVER_URL"] == "https://www.openstreetmap.org":
47+
48+
def get_planet_osm_deleted_users() -> Generator[int, None, None]:
49+
response = requests.get(
50+
"https://planet.openstreetmap.org/users_deleted/users_deleted.txt",
51+
stream=True,
52+
)
53+
username = re.compile(r"^\s*(\d+)\s*$")
54+
try:
55+
for line in response.iter_lines(decode_unicode=True):
56+
match = username.fullmatch(line)
57+
if match:
58+
yield int(match.group(1))
59+
finally:
60+
response.close()
61+
62+
return get_planet_osm_deleted_users()
63+
return None
64+
3565
@staticmethod
3666
def get_osm_details_for_user(user_id: int) -> UserOSMDTO:
3767
"""

0 commit comments

Comments
 (0)