Skip to content

Commit

Permalink
backend: Use planet.osm.org/users_deleted/users_deleted.txt to avoid …
Browse files Browse the repository at this point in the history
…hammering API

Signed-off-by: Taylor Smock <tsmock@meta.com>
  • Loading branch information
tsmock committed Apr 12, 2024
1 parent 00a5dda commit dc29a65
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
38 changes: 27 additions & 11 deletions backend/api/users/resources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from distutils.util import strtobool
from typing import Optional
from collections.abc import Generator

from flask import stream_with_context, Response
from flask_restful import Resource, current_app, request
Expand Down Expand Up @@ -144,20 +145,35 @@ def get(self):
@token_auth.login_required
def delete(self):
if UserService.is_user_an_admin(token_auth.current_user()):

def delete_users():
for user in User.get_all_users_not_paginated():
# We specifically want to remove users that have deleted their OSM accounts.
if OSMService.is_osm_user_gone(user.id):
data = UserService.delete_user_by_id(
user.id, token_auth.current_user()
).to_primitive()
yield f"\u001e{data}\n"

return Response(
stream_with_context(delete_users()),
stream_with_context(UsersAllAPI._delete_users()),
headers={"Content-Type": "application/json-seq"},
)
return "Unauthorized", 401

@staticmethod
def _delete_users() -> Generator[str, None, None]:
# Updated daily
deleted_users = OSMService.get_deleted_users()
if deleted_users:
last_deleted_user = 0
for user in User.get_all_users_not_paginated(User.id):
while last_deleted_user < user.id:
last_deleted_user = next(deleted_users)
if last_deleted_user == user.id:
data = UserService.delete_user_by_id(
user.id, token_auth.current_user()
).to_primitive()
yield f"\u001e{data}\n"
return
# Fall back to hitting the API (if the OSM API is not the default)
for user in User.get_all_users_not_paginated():
# We specifically want to remove users that have deleted their OSM accounts.
if OSMService.is_osm_user_gone(user.id):
data = UserService.delete_user_by_id(
user.id, token_auth.current_user()
).to_primitive()
yield f"\u001e{data}\n"


class UsersQueriesUsernameAPI(Resource):
Expand Down
7 changes: 5 additions & 2 deletions backend/models/postgis/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,12 @@ def get_all_users(query: UserSearchQuery) -> UserSearchDTO:
return dto

@staticmethod
def get_all_users_not_paginated():
def get_all_users_not_paginated(*order):
"""Get all users in DB"""
return db.session.query(User.id).all()
query = db.session.query(User.id)
if not order:
return query.all()
return query.order_by(*order).all()

@staticmethod
def filter_users(user_filter: str, project_id: int, page: int) -> UserFilterDTO:
Expand Down
30 changes: 30 additions & 0 deletions backend/services/users/osm_service.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import re
from collections.abc import Generator
from typing import Optional

import requests
from flask import current_app

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

return False

@staticmethod
def get_deleted_users() -> Optional[Generator[int, None, None]]:
"""
Get the list of deleted users from OpenStreetMap.
This only returns users from the https://www.openstreetmap.org instance.
:return: The deleted users
"""
if current_app.config["OSM_SERVER_URL"] == "https://www.openstreetmap.org":

def get_planet_osm_deleted_users() -> Generator[int, None, None]:
response = requests.get(
"https://planet.openstreetmap.org/users_deleted/users_deleted.txt",
stream=True,
)
username = re.compile(r"^\s*(\d+)\s*$")
try:
for line in response.iter_lines(decode_unicode=True):
match = username.fullmatch(line)
if match:
yield int(match.group(1))
finally:
response.close()

return get_planet_osm_deleted_users()
return None

@staticmethod
def get_osm_details_for_user(user_id: int) -> UserOSMDTO:
"""
Expand Down

0 comments on commit dc29a65

Please sign in to comment.