197 lines
7.7 KiB
Python
197 lines
7.7 KiB
Python
from django.contrib.auth import get_user_model
|
|
from django.test import Client, TestCase
|
|
from django.utils import timezone
|
|
|
|
from workflows.models import UserProfile
|
|
from workflows.roles import ROLE_PLATFORM_OWNER, assign_user_role
|
|
from workflows.totp import generate_totp_token
|
|
|
|
|
|
class AccountUISmokeTests(TestCase):
|
|
def setUp(self):
|
|
self.user = get_user_model().objects.create_user(
|
|
username='profile-user',
|
|
email='profile@example.com',
|
|
password='secret-12345',
|
|
first_name='Profile',
|
|
last_name='User',
|
|
)
|
|
self.client = Client()
|
|
self.client.force_login(self.user)
|
|
|
|
def test_account_profile_page_renders(self):
|
|
response = self.client.get('/account/', HTTP_HOST='localhost')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, 'profile@example.com')
|
|
self.assertContains(response, 'Passwort ändern')
|
|
|
|
def test_password_change_page_renders(self):
|
|
response = self.client.get('/accounts/password_change/', HTTP_HOST='localhost')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, 'Aktuelles Passwort')
|
|
|
|
def test_user_profile_is_created_automatically(self):
|
|
self.assertTrue(UserProfile.objects.filter(user=self.user).exists())
|
|
profile = UserProfile.objects.get(user=self.user)
|
|
self.assertEqual(profile.temporary_role_key, '')
|
|
self.assertIsNone(profile.temporary_role_expires_at)
|
|
self.assertEqual(profile.temporary_role_reason, '')
|
|
|
|
def test_notification_preferences_can_be_updated(self):
|
|
response = self.client.post(
|
|
'/account/',
|
|
{
|
|
'account_form': 'notification_preferences',
|
|
'onboarding_success': 'on',
|
|
'onboarding_failure': '',
|
|
'offboarding_success': '',
|
|
'offboarding_failure': 'on',
|
|
},
|
|
HTTP_HOST='localhost',
|
|
follow=True,
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
profile = UserProfile.objects.get(user=self.user)
|
|
self.assertEqual(
|
|
profile.notification_preferences,
|
|
{
|
|
'onboarding_success': True,
|
|
'onboarding_failure': False,
|
|
'offboarding_success': False,
|
|
'offboarding_failure': True,
|
|
'backup_success': True,
|
|
'backup_failure': True,
|
|
'welcome_email_success': False,
|
|
'welcome_email_failure': False,
|
|
'trial_alerts': True,
|
|
'system_alerts': True,
|
|
},
|
|
)
|
|
|
|
def test_staff_account_notifications_hide_admin_only_categories(self):
|
|
response = self.client.get('/account/', HTTP_HOST='localhost')
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertNotContains(response, 'Backup erfolgreich')
|
|
self.assertNotContains(response, 'Trial-Hinweise')
|
|
self.assertNotContains(response, 'System-Hinweise')
|
|
self.assertContains(response, 'Welcome E-Mail erfolgreich')
|
|
|
|
def test_platform_owner_sees_all_notification_categories(self):
|
|
assign_user_role(self.user, ROLE_PLATFORM_OWNER)
|
|
response = self.client.get('/account/', HTTP_HOST='localhost')
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, 'Backup erfolgreich')
|
|
self.assertContains(response, 'Trial-Hinweise')
|
|
self.assertContains(response, 'System-Hinweise')
|
|
|
|
def test_account_profile_details_can_be_updated(self):
|
|
response = self.client.post(
|
|
'/account/',
|
|
{
|
|
'account_form': 'details',
|
|
'first_name': 'Updated',
|
|
'last_name': 'User',
|
|
'email': 'updated@example.com',
|
|
'phone_number': '030 123456',
|
|
'mobile_number': '0176 123456',
|
|
'job_title': 'IT Manager',
|
|
'department': 'IT',
|
|
'location': 'Berlin',
|
|
'contact_notes': 'Available in the mornings',
|
|
},
|
|
HTTP_HOST='localhost',
|
|
follow=True,
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.user.refresh_from_db()
|
|
profile = self.user.profile
|
|
self.assertEqual(self.user.first_name, 'Updated')
|
|
self.assertEqual(self.user.email, 'updated@example.com')
|
|
self.assertEqual(profile.phone_number, '030 123456')
|
|
self.assertEqual(profile.job_title, 'IT Manager')
|
|
|
|
def test_totp_can_be_enabled_from_account(self):
|
|
response = self.client.post(
|
|
'/account/',
|
|
{
|
|
'account_form': 'totp_enable',
|
|
'current_password': 'secret-12345',
|
|
'verification_code': '000000',
|
|
},
|
|
HTTP_HOST='localhost',
|
|
follow=True,
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.user.refresh_from_db()
|
|
profile = self.user.profile
|
|
pending_secret = self.client.session.get('account_totp_pending_secret')
|
|
self.assertTrue(pending_secret)
|
|
valid_code = generate_totp_token(pending_secret, int(timezone.now().timestamp()))
|
|
|
|
response = self.client.post(
|
|
'/account/',
|
|
{
|
|
'account_form': 'totp_enable',
|
|
'current_password': 'secret-12345',
|
|
'verification_code': valid_code,
|
|
},
|
|
HTTP_HOST='localhost',
|
|
follow=True,
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
profile.refresh_from_db()
|
|
self.assertTrue(profile.totp_enabled)
|
|
self.assertTrue(profile.totp_secret)
|
|
self.assertEqual(len(profile.totp_recovery_codes), 8)
|
|
self.assertContains(response, 'Recovery-Codes')
|
|
|
|
def test_login_requires_totp_when_enabled(self):
|
|
profile = self.user.profile
|
|
profile.totp_secret = 'JBSWY3DPEHPK3PXP'
|
|
profile.totp_enabled = True
|
|
profile.set_recovery_codes(['ABCDE-12345'])
|
|
profile.save(update_fields=['totp_secret', 'totp_enabled', 'totp_recovery_codes', 'updated_at'])
|
|
|
|
client = Client()
|
|
response = client.post(
|
|
'/accounts/login/',
|
|
{'username': 'profile-user', 'password': 'secret-12345'},
|
|
HTTP_HOST='localhost',
|
|
)
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertEqual(response['Location'], '/accounts/login/totp/')
|
|
|
|
response = client.get('/accounts/login/totp/', HTTP_HOST='localhost')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, 'TOTP-Code')
|
|
self.assertContains(response, 'Recovery-Code verwenden')
|
|
|
|
token = generate_totp_token(profile.totp_secret, int(timezone.now().timestamp()))
|
|
response = client.post(
|
|
'/accounts/login/totp/',
|
|
{'otp_code': token},
|
|
HTTP_HOST='localhost',
|
|
)
|
|
self.assertEqual(response.status_code, 302)
|
|
|
|
client = Client()
|
|
first_step = client.post('/accounts/login/', {'username': 'profile-user', 'password': 'secret-12345'}, HTTP_HOST='localhost')
|
|
self.assertEqual(first_step.status_code, 302)
|
|
response = client.post('/accounts/login/totp/', {'recovery_code': 'ABCDE-12345'}, HTTP_HOST='localhost')
|
|
self.assertEqual(response.status_code, 302)
|
|
profile.refresh_from_db()
|
|
self.assertEqual(profile.totp_recovery_codes, [])
|
|
|
|
def test_login_accepts_email_after_password_is_set(self):
|
|
client = Client()
|
|
|
|
response = client.post(
|
|
'/accounts/login/',
|
|
{'username': 'profile@example.com', 'password': 'secret-12345'},
|
|
HTTP_HOST='localhost',
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 302)
|