diff --git a/app/apps.py b/app/apps.py index f0d032f..867cb16 100644 --- a/app/apps.py +++ b/app/apps.py @@ -14,10 +14,12 @@ def load_appstream(): current_apps = db.get_apps("stable") current_apps_beta = db.get_apps("beta") current_categories = db.redis_conn.smembers("categories:index") + current_developers = db.redis_conn.smembers("developers:index") db.initialize() with db.redis_conn.pipeline() as p: p.delete("categories:index", *current_categories) + p.delete("developers:index", *current_developers) for appid in apps: redis_key = f"apps:{appid}" @@ -46,6 +48,10 @@ def load_appstream(): p.sadd("categories:index", category) p.sadd(f"categories:{category}", redis_key) + if developer_name := apps[appid]["stable"].get("developer_name"): + p.sadd("developers:index", developer_name) + p.sadd(f"developers:{developer_name}", redis_key) + p.set(f"apps:{appid}", json.dumps(apps[appid])) for appid in current_apps - set(apps_stable): @@ -108,7 +114,17 @@ def get_category(category: str, repo: str = "stable"): return [(app[repo]["id"]) for app in appdata if repo in app] else: - return [] + return None + + +def get_developer(developer: str, repo: str = "stable"): + if index := db.redis_conn.smembers(f"developers:{developer}"): + json_appdata = db.redis_conn.mget(index) + appdata = [json.loads(app) for app in json_appdata] + + return [(app[repo]["id"]) for app in appdata if repo in app] + else: + return None def search(query: str, repo: str = "stable"): diff --git a/app/db.py b/app/db.py index fef8504..4948bce 100644 --- a/app/db.py +++ b/app/db.py @@ -146,3 +146,7 @@ def get_apps(repo: str = "stable"): elif repo == "beta": apps = {app[5:] for app in redis_conn.smembers("apps:index_beta")} return apps + + +def get_developers(): + return {developer for developer in redis_conn.smembers("developers:index")} diff --git a/app/main.py b/app/main.py index bc334b4..df2b82d 100644 --- a/app/main.py +++ b/app/main.py @@ -47,7 +47,9 @@ def update(): @app.get("/category/{category}") -def get_category(category: schemas.Category): +def get_category( + category: schemas.Category, +): ids = apps.get_category(category) downloads = stats.get_downloads_by_ids(ids) @@ -62,6 +64,34 @@ def get_category(category: schemas.Category): return sorted_ids +@app.get("/developer/") +def get_developers(): + return db.get_developers() + + +@app.get("/developer/{developer}") +def get_developer( + developer: str, + response: Response, +): + ids = apps.get_developer(developer) + + if not ids: + response.status_code = 404 + return response + + downloads = stats.get_downloads_by_ids(ids) + sorted_ids = sorted( + ids, + key=lambda appid: downloads.get(appid, {"downloads_last_month": 0}).get( + "downloads_last_month", 0 + ), + reverse=True, + ) + + return sorted_ids + + @app.get("/appstream") def list_appstream(type: schemas.AppstreamType = "stable"): return apps.list_appstream(type) @@ -112,13 +142,16 @@ def get_popular_days(days: int): @app.get("/feed/recently-updated") def get_recently_updated_apps_feed(type: schemas.AppstreamType = "stable"): return Response( - content=feeds.get_recently_updated_apps_feed(type), media_type="application/rss+xml" + content=feeds.get_recently_updated_apps_feed(type), + media_type="application/rss+xml", ) @app.get("/feed/new") def get_new_apps_feed(type: schemas.AppstreamType = "stable"): - return Response(content=feeds.get_new_apps_feed(type), media_type="application/rss+xml") + return Response( + content=feeds.get_new_apps_feed(type), media_type="application/rss+xml" + ) @app.get("/status", status_code=200) diff --git a/tests/main.py b/tests/main.py index 62452f1..bc48320 100644 --- a/tests/main.py +++ b/tests/main.py @@ -92,6 +92,17 @@ def test_apps_by_non_existent_category(): assert response.status_code == 422 +def test_apps_by_developer(): + response = client.get("/developer/Sugar Labs Community") + assert response.status_code == 200 + assert response.json() == _get_expected_json_result("test_apps_by_developer") + + +def test_apps_by_non_existent_developer(): + response = client.get("/developer/NonExistent") + assert response.status_code == 404 + + def test_appstream_by_appid(): response = client.get("/appstream/org.sugarlabs.Maze") assert response.status_code == 200 diff --git a/tests/results/test_apps_by_developer.json b/tests/results/test_apps_by_developer.json new file mode 100644 index 0000000..f57fe20 --- /dev/null +++ b/tests/results/test_apps_by_developer.json @@ -0,0 +1,3 @@ +[ + "org.sugarlabs.Maze" +]