feat: add community contribution ranks
This commit is contained in:
@@ -77,6 +77,74 @@ def test_profile_and_authorization_roles(client, user_factory, auth_headers):
|
||||
assert client.get("/api/auth/check-mobile", {"mobile": member.mobile}).json()["exists"]
|
||||
|
||||
|
||||
def test_public_profile_hides_personal_fields_until_the_user_opts_in(client, user_factory, auth_headers, event_factory):
|
||||
from apps.events.models import Event, Registration
|
||||
|
||||
member = user_factory(
|
||||
username="public_member",
|
||||
first_name="Public",
|
||||
last_name="Member",
|
||||
email="public.member@example.org",
|
||||
mobile="09195550123",
|
||||
student_id="402123456",
|
||||
year_of_study=1402,
|
||||
bio="A public introduction",
|
||||
)
|
||||
event = event_factory(slug="public-profile-event")
|
||||
Registration.objects.create(event=event, user=member, status=Registration.StatusChoices.CONFIRMED)
|
||||
draft_event = event_factory(slug="private-profile-event", status=Event.StatusChoices.DRAFT)
|
||||
Registration.objects.create(event=draft_event, user=member, status=Registration.StatusChoices.ATTENDED)
|
||||
|
||||
public_path = f"/api/auth/public-profile/{member.username}"
|
||||
hidden_response = client.get(public_path)
|
||||
assert hidden_response.status_code == 200
|
||||
hidden = hidden_response.json()
|
||||
assert hidden["full_name"] == "Public Member"
|
||||
assert hidden["details_visible"] is False
|
||||
assert hidden["mobile"] is None
|
||||
assert hidden["student_id"] is None
|
||||
assert hidden["year_of_study"] is None
|
||||
assert "date_joined" not in hidden
|
||||
assert "blog_activity" not in hidden
|
||||
assert [row["slug"] for row in hidden["events"]] == [event.slug]
|
||||
assert hidden.get("email") is None
|
||||
|
||||
updated = client.put(
|
||||
"/api/auth/profile",
|
||||
data=json.dumps({"show_public_profile_details": True}),
|
||||
content_type="application/json",
|
||||
**auth_headers(member),
|
||||
)
|
||||
assert updated.status_code == 200, updated.content
|
||||
visible = client.get(public_path).json()
|
||||
assert visible["details_visible"] is True
|
||||
assert visible["mobile"] == member.mobile
|
||||
assert visible["student_id"] == member.student_id
|
||||
assert visible["year_of_study"] == member.year_of_study
|
||||
assert visible["email"] == member.email
|
||||
assert "date_joined" not in visible
|
||||
assert "blog_activity" not in visible
|
||||
|
||||
|
||||
def test_public_profile_does_not_expose_placeholder_email(client, user_factory):
|
||||
member = user_factory(
|
||||
username="public_placeholder_email",
|
||||
email="pending-public-placeholder@noemail.local",
|
||||
show_public_profile_details=True,
|
||||
)
|
||||
|
||||
response = client.get(f"/api/auth/public-profile/{member.username}")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json().get("email") is None
|
||||
|
||||
|
||||
def test_public_profile_does_not_expose_inactive_users(client, user_factory):
|
||||
member = user_factory(username="inactive_public_member", is_active=False)
|
||||
response = client.get(f"/api/auth/public-profile/{member.username}")
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_profile_picture_upload_validation_and_delete(client, user_factory, auth_headers, settings, tmp_path):
|
||||
settings.MEDIA_ROOT = tmp_path
|
||||
user = user_factory()
|
||||
@@ -150,6 +218,8 @@ def test_profile_rejects_duplicate_email_and_resolves_education_codes(client, us
|
||||
changed = client.put(path, data=json.dumps({"major": major.code, "university": university.code}),
|
||||
content_type="application/json", **headers)
|
||||
assert changed.status_code == 200, changed.content
|
||||
assert changed.json()["major_code"] == major.code
|
||||
assert changed.json()["university_code"] == university.code
|
||||
user.refresh_from_db()
|
||||
assert user.major == major and user.university == university
|
||||
assert client.put(path, data=json.dumps({"major": None, "university": None}),
|
||||
@@ -158,6 +228,92 @@ def test_profile_rejects_duplicate_email_and_resolves_education_codes(client, us
|
||||
assert user.major is None and user.university is None
|
||||
|
||||
|
||||
def test_profile_update_allows_username_changes_and_limits_plain_text_bio(client, user_factory, auth_headers):
|
||||
member = user_factory(username="before_edit")
|
||||
another = user_factory(username="already_taken")
|
||||
headers = auth_headers(member)
|
||||
path = "/api/auth/profile"
|
||||
|
||||
changed = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "after_edit", "bio": "A short plain text introduction"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
assert changed.status_code == 200, changed.content
|
||||
assert changed.json()["username"] == "after_edit"
|
||||
|
||||
duplicate = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": another.username}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
assert duplicate.status_code == 400
|
||||
|
||||
too_long = client.put(
|
||||
path,
|
||||
data=json.dumps({"bio": "a" * 501}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
assert too_long.status_code == 422
|
||||
at_limit = client.put(
|
||||
path,
|
||||
data=json.dumps({"bio": "a" * 500}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
assert at_limit.status_code == 200, at_limit.content
|
||||
|
||||
|
||||
def test_profile_username_changes_follow_public_username_rules(client, user_factory, auth_headers):
|
||||
member = user_factory(username="amir")
|
||||
user_factory(username="already_taken")
|
||||
headers = auth_headers(member)
|
||||
path = "/api/auth/profile"
|
||||
|
||||
unchanged_legacy_name = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "amir"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
too_short = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "abc1"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
invalid_characters = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "valid-name"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
duplicate = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "already_taken"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
available = client.put(
|
||||
path,
|
||||
data=json.dumps({"username": "valid_name42"}),
|
||||
content_type="application/json",
|
||||
**headers,
|
||||
)
|
||||
case_insensitive_availability = client.get("/api/auth/check-username?username=ALREADY_TAKEN")
|
||||
|
||||
assert unchanged_legacy_name.status_code == 200
|
||||
assert too_short.status_code == 400
|
||||
assert invalid_characters.status_code == 400
|
||||
assert duplicate.status_code == 400
|
||||
assert available.status_code == 200, available.content
|
||||
assert available.json()["username"] == "valid_name42"
|
||||
assert case_insensitive_availability.status_code == 200
|
||||
assert case_insensitive_availability.json()["exists"] is True
|
||||
|
||||
def test_authorization_rejects_unknown_group_and_refresh_bad_token(client, user_factory, auth_headers):
|
||||
admin = user_factory(is_superuser=True, is_staff=True)
|
||||
member = user_factory()
|
||||
|
||||
Reference in New Issue
Block a user