Files
opencloud-backend/tests/test_profiles.py
T

371 lines
12 KiB
Python

import uuid
import pytest
from fastapi.testclient import TestClient
from tests.conftest import (
admin_token,
approve_cloud,
bearer,
png_bytes,
register_and_confirm,
)
# ---------------------------------------------------------------------------
# get profile
# ---------------------------------------------------------------------------
def test_get_profile(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"prof-{uuid.uuid4().hex[:8]}@example.com",
"profpass1", "资料展示",
)
r = client.get(f"/api/v1/profiles/{info['user_id']}")
assert r.status_code == 200
assert r.json()["username"] == "资料展示"
def test_get_nonexistent_profile(client: TestClient) -> None:
r = client.get(f"/api/v1/profiles/{uuid.uuid4()}")
assert r.status_code == 404
# ---------------------------------------------------------------------------
# update my profile
# ---------------------------------------------------------------------------
def test_update_me(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"updme-{uuid.uuid4().hex[:8]}@example.com",
"updmepass", "原昵称",
)
r = client.patch(
"/api/v1/profiles/me",
headers=bearer(info["token"]),
json={"username": "新昵称"},
)
assert r.status_code == 200
assert r.json()["username"] == "新昵称"
def test_update_me_short_username(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"shortname-{uuid.uuid4().hex[:8]}@example.com",
"shortname", "短名字测试",
)
r = client.patch(
"/api/v1/profiles/me",
headers=bearer(info["token"]),
json={"username": "A"},
)
assert r.status_code == 422
def test_update_me_duplicate_username(client: TestClient, monkeypatch) -> None:
register_and_confirm(
client, monkeypatch,
f"dupname-u1-{uuid.uuid4().hex[:8]}@example.com",
"pass11112", "已占用的名字",
)
info2 = register_and_confirm(
client, monkeypatch,
f"dupname-u2-{uuid.uuid4().hex[:8]}@example.com",
"pass22223", "第二人",
)
r = client.patch(
"/api/v1/profiles/me",
headers=bearer(info2["token"]),
json={"username": "已占用的名字"},
)
assert r.status_code == 409
assert "昵称" in r.json()["detail"]
# ---------------------------------------------------------------------------
# get user clouds
# ---------------------------------------------------------------------------
def test_get_user_clouds_public(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"pubcloud-{uuid.uuid4().hex[:8]}@example.com",
"pubcloud1", "公开云主",
)
ur = client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "1", "is_hidden": "false"},
)
approve_cloud(client, admin_token(client), ur.json()["cloud"]["id"])
r = client.get(f"/api/v1/profiles/{info['user_id']}/clouds")
assert r.status_code == 200
assert r.json()["total"] >= 1
for item in r.json()["items"]:
assert item["status"] == "approved"
def test_get_my_clouds_via_me(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"myclouds-{uuid.uuid4().hex[:8]}@example.com",
"myclouds1", "me 云图",
)
client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "1", "is_hidden": "false"},
)
r = client.get("/api/v1/profiles/me/clouds", headers=bearer(info["token"]))
assert r.status_code == 200
assert r.json()["total"] >= 1
# 本人可以看到 pending 状态
assert r.json()["items"][0]["status"] == "pending"
def test_get_my_clouds_via_me_unauthenticated(client: TestClient) -> None:
r = client.get("/api/v1/profiles/me/clouds")
assert r.status_code == 401
def test_get_user_clouds_as_owner(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"owncloud-{uuid.uuid4().hex[:8]}@example.com",
"owncloud1", "私有云主",
)
ur = client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "1", "is_hidden": "false"},
)
approve_cloud(client, admin_token(client), ur.json()["cloud"]["id"])
r = client.get(
f"/api/v1/profiles/{info['user_id']}/clouds",
headers=bearer(info["token"]),
)
assert r.status_code == 200
assert r.json()["total"] >= 1
def test_get_nonexistent_user_clouds(client: TestClient) -> None:
r = client.get(f"/api/v1/profiles/{uuid.uuid4()}/clouds")
assert r.status_code == 404
# ---------------------------------------------------------------------------
# /me profile shortcut
# ---------------------------------------------------------------------------
def test_get_my_profile_via_me(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"me-prof-{uuid.uuid4().hex[:8]}@example.com",
"meprof12", "me 资料",
)
r = client.get("/api/v1/profiles/me", headers=bearer(info["token"]))
assert r.status_code == 200
assert r.json()["username"] == "me 资料"
assert r.json()["id"] == info["user_id"]
def test_get_my_profile_via_me_unauthenticated(client: TestClient) -> None:
r = client.get("/api/v1/profiles/me")
assert r.status_code == 401
# ---------------------------------------------------------------------------
# stats
# ---------------------------------------------------------------------------
def test_get_my_stats_via_me(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"mestats-{uuid.uuid4().hex[:8]}@example.com",
"mestatsp", "me 统计",
)
client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "1", "is_hidden": "false"},
)
r = client.get("/api/v1/profiles/me/stats", headers=bearer(info["token"]))
assert r.status_code == 200
body = r.json()
assert body["cloud_count"] == 1
assert body["username"] == "me 统计"
assert body["user_id"] == info["user_id"]
def test_get_my_stats_via_user_id(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"selfstats-{uuid.uuid4().hex[:8]}@example.com",
"selfstat", "自统计",
)
r = client.get(
f"/api/v1/profiles/{info['user_id']}/stats",
headers=bearer(info["token"]),
)
assert r.status_code == 200
assert r.json()["user_id"] == info["user_id"]
def test_get_user_stats_admin(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"stats-{uuid.uuid4().hex[:8]}@example.com",
"statspass", "统计用户",
)
ur1 = client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "1", "is_hidden": "false"},
)
approve_cloud(client, admin_token(client), ur1.json()["cloud"]["id"])
client.post(
"/api/v1/clouds",
headers=bearer(info["token"]),
files={"image": ("cloud.png", png_bytes(), "image/png")},
data={"cloud_type_id": "2", "is_hidden": "false"},
)
r = client.get(
f"/api/v1/profiles/{info['user_id']}/stats",
headers=bearer(admin_token(client)),
)
assert r.status_code == 200
body = r.json()
assert body["cloud_count"] == 2
assert body["public_cloud_count"] == 1
assert body["collection_count"] == 2
assert body["username"] == "统计用户"
def test_get_user_stats_other_user_forbidden(client: TestClient, monkeypatch) -> None:
info_a = register_and_confirm(
client, monkeypatch,
f"stats-a-{uuid.uuid4().hex[:8]}@example.com",
"statsapp1", "A 的统计",
)
info_b = register_and_confirm(
client, monkeypatch,
f"stats-b-{uuid.uuid4().hex[:8]}@example.com",
"statsbpp2", "B 的统计",
)
r = client.get(
f"/api/v1/profiles/{info_a['user_id']}/stats",
headers=bearer(info_b["token"]),
)
assert r.status_code == 403
def test_get_user_stats_unauthenticated(client: TestClient) -> None:
r = client.get(f"/api/v1/profiles/{uuid.uuid4()}/stats")
assert r.status_code == 401
def test_get_user_stats_nonexistent(client: TestClient) -> None:
r = client.get(
f"/api/v1/profiles/{uuid.uuid4()}/stats",
headers=bearer(admin_token(client)),
)
assert r.status_code == 404
# ---------------------------------------------------------------------------
# avatar
# ---------------------------------------------------------------------------
def test_upload_avatar(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"avatar-{uuid.uuid4().hex[:8]}@example.com",
"avatarp12", "头像用户",
)
r = client.post(
"/api/v1/profiles/me/avatar",
headers=bearer(info["token"]),
files={"image": ("avatar.png", png_bytes(), "image/png")},
)
assert r.status_code == 200
body = r.json()
assert body["avatar_url"] is not None
assert "avatars/" in body["avatar_url"]
def test_replace_avatar(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"avat2-{uuid.uuid4().hex[:8]}@example.com",
"avat2p12", "换头像",
)
r1 = client.post(
"/api/v1/profiles/me/avatar",
headers=bearer(info["token"]),
files={"image": ("avatar.png", png_bytes(), "image/png")},
)
assert r1.status_code == 200
assert r1.json()["avatar_url"] is not None
r2 = client.post(
"/api/v1/profiles/me/avatar",
headers=bearer(info["token"]),
files={"image": ("avatar2.png", png_bytes(), "image/png")},
)
assert r2.status_code == 200
assert r2.json()["avatar_url"] is not None
def test_delete_avatar(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"avat3-{uuid.uuid4().hex[:8]}@example.com",
"avat3p12", "删头像",
)
client.post(
"/api/v1/profiles/me/avatar",
headers=bearer(info["token"]),
files={"image": ("avatar.png", png_bytes(), "image/png")},
)
r = client.delete("/api/v1/profiles/me/avatar", headers=bearer(info["token"]))
assert r.status_code == 200
assert r.json()["avatar_url"] is None
def test_delete_avatar_not_found(client: TestClient, monkeypatch) -> None:
info = register_and_confirm(
client, monkeypatch,
f"avat4-{uuid.uuid4().hex[:8]}@example.com",
"avat4p12", "没头像删",
)
r = client.delete("/api/v1/profiles/me/avatar", headers=bearer(info["token"]))
assert r.status_code == 404
def test_upload_avatar_unauthenticated(client: TestClient) -> None:
r = client.post(
"/api/v1/profiles/me/avatar",
files={"image": ("avatar.png", png_bytes(), "image/png")},
)
assert r.status_code == 401
def test_delete_avatar_unauthenticated(client: TestClient) -> None:
r = client.delete("/api/v1/profiles/me/avatar")
assert r.status_code == 401