fix payement link and gallery image
This commit is contained in:
1 parent
de3135b588
commit
1cbbbbd0dc
24 files changed
+654
-116
No files matched your search
@@ -0,0 +1,153 @@
|
||||
import json
|
||||
import uuid
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from django.test import Client
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.accounts.models import TicketMagicLink
|
||||
from apps.messaging.models import Message, MessageReadReceipt
|
||||
from apps.tickets.models import TicketReadState
|
||||
from apps.tickets.sharing import revoke_staff_share, share_staff_message, share_staff_ticket
|
||||
from tests.test_staff_sharing import make_sharing_case
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def seen_case(settings):
|
||||
settings.PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher']
|
||||
case = make_sharing_case()
|
||||
case['reply'] = Message.objects.create(ticket=case['ticket'], author=case['sender'], body='پاسخ قابل مشاهده')
|
||||
return case
|
||||
|
||||
|
||||
@pytest.mark.parametrize('route', ['detail', 'messages', 'poll'])
|
||||
def test_staff_get_requests_never_mark_messages_or_ticket_read(client, seen_case, route):
|
||||
c = seen_case
|
||||
share_staff_ticket(c['ticket'], c['sender'], c['recipient'], 'VIEW_ONLY')
|
||||
client.force_login(c['recipient'])
|
||||
response = client.get(reverse('staff_tickets:' + route, args=[c['ticket'].public_id]))
|
||||
assert response.status_code == 200
|
||||
assert not MessageReadReceipt.objects.filter(user=c['recipient']).exists()
|
||||
assert not TicketReadState.objects.filter(user=c['recipient']).exists()
|
||||
|
||||
|
||||
def test_staff_acknowledgement_is_scoped_idempotent_and_rechecked_after_revocation(client, seen_case):
|
||||
c = seen_case
|
||||
grant = share_staff_message(c['selected'], c['sender'], c['recipient'])
|
||||
client.force_login(c['recipient'])
|
||||
url = reverse('staff_tickets:read_shares', args=[c['ticket'].public_id])
|
||||
values = [str(c['selected'].public_id), str(c['reply'].public_id), str(uuid.uuid4()), 'bad-uuid']
|
||||
for _ in range(2):
|
||||
response = client.post(url, {'message_ids': values})
|
||||
assert response.status_code == 200
|
||||
assert response.json()['read_ids'] == [str(c['selected'].public_id)]
|
||||
assert list(MessageReadReceipt.objects.filter(user=c['recipient']).values_list('message_id', flat=True)) == [c['selected'].pk]
|
||||
assert not TicketReadState.objects.filter(user=c['recipient']).exists()
|
||||
grant.refresh_from_db()
|
||||
assert grant.view_count == 1
|
||||
revoke_staff_share(grant, c['sender'])
|
||||
assert client.post(url, {'message_ids': values}).status_code == 403
|
||||
assert client.get(reverse('staff_tickets:poll', args=[c['ticket'].public_id])).status_code == 403
|
||||
assert not MessageReadReceipt.objects.filter(message=c['reply'], user=c['recipient']).exists()
|
||||
|
||||
|
||||
def test_staff_ticket_read_state_requires_acknowledging_the_latest_message(client, seen_case):
|
||||
c = seen_case
|
||||
client.force_login(c['sender'])
|
||||
url = reverse('staff_tickets:read_shares', args=[c['ticket'].public_id])
|
||||
client.post(url, {'message_ids': [str(c['selected'].public_id)]})
|
||||
assert not TicketReadState.objects.filter(user=c['sender']).exists()
|
||||
client.post(url, {'message_ids': [str(c['reply'].public_id)]})
|
||||
assert TicketReadState.objects.get(user=c['sender']).last_read_message_id == c['reply'].pk
|
||||
assert not MessageReadReceipt.objects.filter(message=c['reply'], user=c['sender']).exists()
|
||||
|
||||
|
||||
def test_another_colleagues_read_state_does_not_hide_my_unread_ticket(seen_case):
|
||||
from apps.tickets.selectors import filter_staff_tickets, staff_ticket_rows
|
||||
c = seen_case
|
||||
share_staff_ticket(c['ticket'], c['sender'], c['recipient'], 'VIEW_ONLY')
|
||||
TicketReadState.objects.create(ticket=c['ticket'], user=c['sender'], last_read_at=timezone.now(), last_read_message=c['reply'])
|
||||
unread = filter_staff_tickets(staff_ticket_rows(c['recipient']), c['recipient'], {'unread': '1'})
|
||||
assert unread.filter(pk=c['ticket'].pk).exists()
|
||||
own_state = TicketReadState.objects.create(ticket=c['ticket'], user=c['recipient'], last_read_at=timezone.now(), last_read_message=c['reply'])
|
||||
assert not unread.filter(pk=c['ticket'].pk).exists()
|
||||
own_state.last_read_at = c['ticket'].last_activity_at - timedelta(seconds=1)
|
||||
own_state.save(update_fields=['last_read_at'])
|
||||
assert unread.filter(pk=c['ticket'].pk).exists()
|
||||
|
||||
|
||||
def test_customer_receipts_exclude_own_deleted_internal_and_other_ticket_messages(client, seen_case):
|
||||
c = seen_case
|
||||
deleted = Message.objects.create(ticket=c['ticket'], author=c['sender'], body='حذفشده', deleted_at=timezone.now())
|
||||
from apps.tickets.services import create_ticket
|
||||
other = create_ticket(customer=c['customer'], category=c['ticket'].category, subject='تیکت دیگر', body='پیام تیکت دیگر')
|
||||
foreign = Message.objects.create(ticket=other, author=c['sender'], body='پاسخ خصوصی تیکت دیگر')
|
||||
client.force_login(c['customer'])
|
||||
for route in ['detail', 'messages', 'poll']:
|
||||
assert client.get(reverse('tickets:' + route, args=[c['ticket'].public_id])).status_code == 200
|
||||
assert not MessageReadReceipt.objects.filter(user=c['customer']).exists()
|
||||
identifiers = [str(value) for value in c['ticket'].ticket_messages.values_list('public_id', flat=True)]
|
||||
identifiers += [str(foreign.public_id), str(uuid.uuid4()), 'not-a-uuid', 42, None]
|
||||
url = reverse('tickets:read', args=[c['ticket'].public_id])
|
||||
response = client.post(url, json.dumps({'message_ids': identifiers}), content_type='application/json')
|
||||
assert response.status_code == 200
|
||||
assert list(MessageReadReceipt.objects.filter(user=c['customer']).values_list('message_id', flat=True)) == [c['reply'].pk]
|
||||
assert not MessageReadReceipt.objects.filter(message=deleted).exists()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('payload', ['not json', 'null', '[]', '{"message_ids":"bad"}', '{"message_ids":{}}'])
|
||||
@pytest.mark.parametrize('staff', [True, False])
|
||||
def test_malformed_read_payloads_return_400_without_recording_reads(client, seen_case, payload, staff):
|
||||
c = seen_case
|
||||
client.force_login(c['sender'] if staff else c['customer'])
|
||||
url = reverse('staff_tickets:read_shares' if staff else 'tickets:read', args=[c['ticket'].public_id])
|
||||
assert client.post(url, payload, content_type='application/json').status_code == 400
|
||||
assert not MessageReadReceipt.objects.exists()
|
||||
values = [str(c['reply'].public_id)] * 101
|
||||
assert client.post(url, json.dumps({'message_ids': values}), content_type='application/json').status_code == 400
|
||||
|
||||
|
||||
def test_read_acknowledgements_keep_csrf_and_magic_link_scope(seen_case):
|
||||
c = seen_case
|
||||
strict = Client(enforce_csrf_checks=True)
|
||||
strict.force_login(c['sender'])
|
||||
staff_url = reverse('staff_tickets:read_shares', args=[c['ticket'].public_id])
|
||||
assert strict.post(staff_url, {'message_ids': [str(c['selected'].public_id)]}).status_code == 403
|
||||
anonymous = Client()
|
||||
token = TicketMagicLink.issue(c['ticket'])
|
||||
assert anonymous.get(reverse('accounts:magic', args=[token])).status_code == 302
|
||||
url = reverse('tickets:read', args=[c['ticket'].public_id])
|
||||
assert anonymous.post(url, json.dumps({'message_ids': [str(c['reply'].public_id)]}), content_type='application/json').status_code == 200
|
||||
assert MessageReadReceipt.objects.filter(message=c['reply'], user=c['customer']).exists()
|
||||
assert '_auth_user_id' not in anonymous.session
|
||||
|
||||
|
||||
def test_polling_backlog_does_not_skip_messages_after_the_first_batch(client, seen_case):
|
||||
c = seen_case
|
||||
client.force_login(c['sender'])
|
||||
url = reverse('staff_tickets:poll', args=[c['ticket'].public_id])
|
||||
initial = client.get(url).json()
|
||||
batch = [Message.objects.create(ticket=c['ticket'], author=c['customer'], body=f'پیام صف {i}') for i in range(55)]
|
||||
first = client.get(url, {'version': initial['version'], 'cursor': initial['cursor']}).json()
|
||||
assert not first['replace'] and first['cursor'] == str(batch[49].public_id)
|
||||
second = client.get(url, {'version': first['version'], 'cursor': first['cursor']}).json()
|
||||
assert not second['replace'] and second['cursor'] == str(batch[-1].public_id)
|
||||
assert batch[-1].body in second['html']
|
||||
assert not MessageReadReceipt.objects.exists()
|
||||
|
||||
|
||||
def test_polling_detects_editing_an_older_message_even_with_a_new_reply(client, seen_case):
|
||||
from apps.messaging.services import edit_message
|
||||
c = seen_case
|
||||
client.force_login(c['customer'])
|
||||
url = reverse('tickets:poll', args=[c['ticket'].public_id])
|
||||
initial = client.get(url).json()
|
||||
edit_message(c['selected'].pk, c['customer'], 'متن اصلاحشده پیام قبلی')
|
||||
Message.objects.create(ticket=c['ticket'], author=c['sender'], body='پاسخ همزمان')
|
||||
response = client.get(url, {'version': initial['version'], 'cursor': initial['cursor']}).json()
|
||||
assert response['changed'] and response['replace']
|
||||
assert 'متن اصلاحشده پیام قبلی' in response['html'] and 'پاسخ همزمان' in response['html']
|
||||
Reference in new issue
Block a user