285 lines
9.7 KiB
Python
285 lines
9.7 KiB
Python
|
|
from django.urls import reverse
|
|
from django.core import mail
|
|
|
|
from rich.pretty import pprint
|
|
|
|
from bs4 import BeautifulSoup
|
|
|
|
from django.contrib.auth.models import Group
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def create_users(db, django_user_model):
|
|
user1 = django_user_model.objects.create_user(
|
|
"user1", "user1@user.com", "password"
|
|
)
|
|
user2 = django_user_model.objects.create_user(
|
|
"user2", "user2@user.com", "password"
|
|
)
|
|
#g = Group.objects.create(name="cid_user_manager")
|
|
#g.save()
|
|
#user.groups.add(g)
|
|
return user1, user2
|
|
|
|
@pytest.fixture
|
|
def create_cid_manager(db, django_user_model):
|
|
user = django_user_model.objects.create_user(
|
|
"cid_user", "cid@user.com", "password1234"
|
|
)
|
|
g = Group.objects.create(name="cid_user_manager")
|
|
g.save()
|
|
user.groups.add(g)
|
|
return user
|
|
|
|
def test_profile_access_and_management(db, client, create_users, create_cid_manager):
|
|
|
|
response = client.get(reverse(f"profile"))
|
|
|
|
# should redirect to login page
|
|
assert response.status_code == 302
|
|
assert "accounts/login/" in response.url
|
|
# Test login
|
|
|
|
client.login(username="user1", password="password")
|
|
|
|
response = client.get(reverse(f"profile"))
|
|
|
|
assert response.status_code == 200
|
|
|
|
soup = BeautifulSoup(response.content, "html.parser")
|
|
|
|
assert soup.find(id="username").text == "user1"
|
|
assert soup.find(id="email").text == "user1@user.com"
|
|
|
|
# Check the links to change password and update profile
|
|
password_url = soup.find(id="password-change")["href"]
|
|
print(password_url)
|
|
password_change_response = client.get(password_url)
|
|
assert password_change_response.status_code == 200
|
|
|
|
password_soup = BeautifulSoup(password_change_response.content, "html.parser")
|
|
assert "Old password" in password_soup.text
|
|
assert "New password" in password_soup.text
|
|
|
|
update_profile = soup.find(id="update-profile-link")["href"]
|
|
|
|
assert update_profile == reverse("account_profile_update", kwargs={"slug": "user1"})
|
|
|
|
# check we can't access another users profile
|
|
response_fail = client.get(reverse("account_profile_update", kwargs={"slug": "user2"}))
|
|
assert response_fail.status_code == 404
|
|
print(response_fail.content)
|
|
|
|
# And that we can access our own
|
|
update_profile_response = client.get(reverse("account_profile_update", kwargs={"slug": "user1"}))
|
|
assert update_profile_response.status_code == 200
|
|
|
|
assert "peninsula_trainee" not in BeautifulSoup(update_profile_response.content, "html.parser").text
|
|
|
|
update_response = client.post(reverse("account_profile_update", kwargs={"slug": "user1"}), {
|
|
"registration_number": 1234567
|
|
})
|
|
assert update_response.status_code == 302
|
|
# we reirect back to profile page on form submission
|
|
assert update_response.url == reverse("profile")
|
|
|
|
# check that the form has updated
|
|
update_profile_response = client.get(reverse("account_profile_update", kwargs={"slug": "user1"}))
|
|
assert BeautifulSoup(update_profile_response.content, "html.parser").find(id="id_registration_number")["value"]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_create_user_reuses_existing_account(client, create_cid_manager, django_user_model):
|
|
existing_user = django_user_model.objects.create_user(
|
|
username="existing@example.com",
|
|
email="existing@example.com",
|
|
password="password123",
|
|
first_name="Old",
|
|
last_name="Name",
|
|
)
|
|
|
|
client.force_login(create_cid_manager)
|
|
|
|
response = client.post(
|
|
reverse("create_user"),
|
|
{
|
|
"username": "existing@example.com",
|
|
"first_name": "Updated",
|
|
"last_name": "User",
|
|
"grade": "",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 302
|
|
assert response.url == reverse("accounts_list")
|
|
|
|
existing_user.refresh_from_db()
|
|
assert existing_user.first_name == "Updated"
|
|
assert existing_user.last_name == "User"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_cid_manager_can_send_password_reset_from_account_profile(client, create_cid_manager, django_user_model):
|
|
managed_user = django_user_model.objects.create_user(
|
|
username="managed-user",
|
|
email="managed@example.com",
|
|
password="password123",
|
|
)
|
|
|
|
client.force_login(create_cid_manager)
|
|
response = client.post(
|
|
reverse("account_send_password_reset", kwargs={"slug": managed_user.username}),
|
|
{"next": reverse("account_profile", kwargs={"slug": managed_user.username})},
|
|
)
|
|
|
|
assert response.status_code == 302
|
|
assert "password_reset_action=sent" in response.url
|
|
assert len(mail.outbox) == 1
|
|
assert mail.outbox[0].to == ["managed@example.com"]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_people_page_and_user_search(client, create_users, create_cid_manager):
|
|
# Log in as cid_user_manager
|
|
client.force_login(create_cid_manager)
|
|
|
|
# 1. Test standard GET request to /people page
|
|
response = client.get(reverse("people"))
|
|
assert response.status_code == 200
|
|
assert b"Quick User Search" in response.content
|
|
assert b"hx-indicator=\"#search-indicator\"" in response.content
|
|
|
|
# 2. Test HTMX GET request with empty query
|
|
response_empty = client.get(
|
|
reverse("people"),
|
|
{"q": ""},
|
|
HTTP_HX_REQUEST="true",
|
|
)
|
|
assert response_empty.status_code == 200
|
|
assert response_empty.content == b""
|
|
|
|
# 3. Test HTMX GET request with matching query
|
|
user1, user2 = create_users
|
|
response_search = client.get(
|
|
reverse("people"),
|
|
{"q": "user1"},
|
|
HTTP_HX_REQUEST="true",
|
|
)
|
|
assert response_search.status_code == 200
|
|
assert b"user1" in response_search.content
|
|
assert b"user1@user.com" in response_search.content
|
|
assert b"Actions" in response_search.content
|
|
|
|
# 4. Test HTMX GET request with no matching users
|
|
response_no_match = client.get(
|
|
reverse("people"),
|
|
{"q": "nonexistent_username_xyz"},
|
|
HTTP_HX_REQUEST="true",
|
|
)
|
|
assert response_no_match.status_code == 200
|
|
assert b"No users found matching" in response_no_match.content
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_hide_exams_and_collections(client, create_users):
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from physics.models import Exam as PhysicsExam
|
|
from atlas.models import CaseCollection
|
|
from generic.models import UserHiddenItem
|
|
|
|
user1, user2 = create_users
|
|
|
|
# 1. Create a PhysicsExam and associate with user1
|
|
exam = PhysicsExam.objects.create(
|
|
name="Test Physics Exam", exam_mode=True, active=True
|
|
)
|
|
user1.user_physics_exams.add(exam)
|
|
|
|
# 2. Create a CaseCollection and associate with user1
|
|
collection = CaseCollection.objects.create(
|
|
name="Test Case Collection", exam_mode=True, active=True
|
|
)
|
|
user1.user_casecollection_exams.add(collection)
|
|
|
|
# Log in as user1
|
|
client.force_login(user1)
|
|
|
|
# Verify they are visible on user scores page initially
|
|
response = client.get(reverse("user_scores"))
|
|
assert response.status_code == 200
|
|
assert b"Test Physics Exam" in response.content
|
|
|
|
# Load atlas collections partial
|
|
response_cc = client.get(reverse("atlas:user_collections"))
|
|
assert response_cc.status_code == 200
|
|
assert b"Test Case Collection" in response_cc.content
|
|
|
|
# 3. Hide the PhysicsExam
|
|
exam_ct = ContentType.objects.get_for_model(PhysicsExam)
|
|
response_hide_exam = client.post(
|
|
reverse("generic:toggle_hide_item"),
|
|
{"content_type_id": exam_ct.id, "object_id": exam.id},
|
|
)
|
|
assert response_hide_exam.status_code == 200
|
|
assert response_hide_exam.headers.get("HX-Refresh") == "true"
|
|
|
|
# Verify UserHiddenItem exists
|
|
assert UserHiddenItem.objects.filter(
|
|
user=user1, content_type=exam_ct, object_id=exam.id
|
|
).exists()
|
|
|
|
# Verify exam is hidden now from standard user_scores
|
|
response_hidden = client.get(reverse("user_scores"))
|
|
assert response_hidden.status_code == 200
|
|
assert b"Test Physics Exam" not in response_hidden.content
|
|
|
|
# But present when show_hidden=true is requested
|
|
response_show_hidden = client.get(reverse("user_scores") + "?show_hidden=true")
|
|
assert response_show_hidden.status_code == 200
|
|
assert b"Test Physics Exam" in response_show_hidden.content
|
|
assert b"Hidden" in response_show_hidden.content
|
|
|
|
# 4. Hide the CaseCollection
|
|
cc_ct = ContentType.objects.get_for_model(CaseCollection)
|
|
response_hide_cc = client.post(
|
|
reverse("generic:toggle_hide_item"),
|
|
{"content_type_id": cc_ct.id, "object_id": collection.pk},
|
|
)
|
|
assert response_hide_cc.status_code == 200
|
|
assert response_hide_cc.headers.get("HX-Refresh") == "true"
|
|
|
|
assert UserHiddenItem.objects.filter(
|
|
user=user1, content_type=cc_ct, object_id=collection.pk
|
|
).exists()
|
|
|
|
# Verify collection is hidden from normal view
|
|
response_cc_hidden = client.get(reverse("atlas:user_collections"))
|
|
assert response_cc_hidden.status_code == 200
|
|
assert b"Test Case Collection" not in response_cc_hidden.content
|
|
|
|
# Verify collection is visible in show_hidden view
|
|
response_cc_show_hidden = client.get(reverse("atlas:user_collections") + "?show_hidden=true")
|
|
assert response_cc_show_hidden.status_code == 200
|
|
assert b"Test Case Collection" in response_cc_show_hidden.content
|
|
assert b"Hidden" in response_cc_show_hidden.content
|
|
|
|
# 5. Unhide the PhysicsExam by toggling again
|
|
response_unhide_exam = client.post(
|
|
reverse("generic:toggle_hide_item"),
|
|
{"content_type_id": exam_ct.id, "object_id": exam.id},
|
|
)
|
|
assert response_unhide_exam.status_code == 200
|
|
assert not UserHiddenItem.objects.filter(
|
|
user=user1, content_type=exam_ct, object_id=exam.id
|
|
).exists()
|
|
|
|
response_unhidden = client.get(reverse("user_scores"))
|
|
assert response_unhidden.status_code == 200
|
|
assert b"Test Physics Exam" in response_unhidden.content
|
|
|
|
|
|
|
|
|