Files
MathApp/content/tests_paywall.py
Zareian 64c4c09326 Paywall: first unit of each grade free; 1/3/6-month subscriptions; AI sold separately
- content: unit_is_free/has_unit_access; questions, node quiz, answer and lesson/node
  complete return 402 subscription_required outside the first unit without an active
  subscription. /api/home units carry requiresSubscription.
- subscription.0013: monthly 498k, quarterly 798k, six-month 1,298k toman, unlimited
  hearts, 3 AI questions/day; packs stay on sale for more questions.
- AI_DAILY_QUOTA_FREE default 3 -> 2.
- /api/subscription/status adds planTitle, planDurationDays, aiDailyQuota.
- tests: content/tests_paywall.py; existing unlock-order tests get a subscription.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:19:02 +03:30

71 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
فصلِ اولِ هر پایه رایگان است و بقیه اشتراکِ زمانی می‌خواهند (۲۰۲۶-۱۰-۱۰).
بازی‌کردنِ فصلِ قفل از هر مسیری (سوال‌های درس، آزمونِ جزیره، جواب، پایانِ درس/جزیره) ۴۰۲ می‌گیرد.
"""
from django.core.cache import cache
from django.test import TestCase
from django.utils import timezone
from rest_framework.test import APIClient
from accounts.authentication import issue_access_token
from accounts.models import User
from subscription.models import Subscription
from .models import Choice, Grade, Lesson, Node, Question, Unit
class PaywallTests(TestCase):
def setUp(self):
cache.clear()
grade = Grade.objects.create(title='پایه نهم', icon='', color='')
self.free = self._node(Unit.objects.create(grade=grade, title='فصل ۱', order=1))
self.paid = self._node(Unit.objects.create(grade=grade, title='فصل ۲', order=2))
self.user = User.objects.create(phone='09120007901', grade_id=grade.id)
self.client = APIClient()
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {issue_access_token(self.user.id)}')
def _node(self, unit):
node = Node.objects.create(unit=unit, title=unit.title, order=1)
lesson = Lesson.objects.create(node=node, title='درس')
q = Question.objects.create(lesson=lesson, type='multiple_choice', prompt='؟')
self.right = Choice.objects.create(question=q, value='۱', is_correct=True)
node.q, node.choice, node.lesson = q, self.right, lesson
return node
def _every_route(self, node):
return [
self.client.get(f'/api/lessons/{node.lesson.id}/questions').status_code,
self.client.get(f'/api/nodes/{node.id}/quiz').status_code,
self.client.post(f'/api/questions/{node.q.id}/answer', {'selectedOptionId': str(node.choice.id)},
format='json').status_code,
self.client.post(f'/api/nodes/{node.id}/quiz/complete', {'correctCount': 1, 'totalQuestions': 1},
format='json').status_code,
]
def test_the_second_unit_is_closed_without_a_subscription(self):
self.assertEqual(self._every_route(self.paid), [402, 402, 402, 402])
home = self.client.get('/api/home').json()
self.assertEqual([u['requiresSubscription'] for u in home['units']], [False, True])
def test_the_first_unit_is_free(self):
self.assertNotIn(402, self._every_route(self.free))
def test_an_active_subscription_opens_everything_and_an_expired_one_does_not(self):
sub = Subscription.objects.create(user_id=self.user.id, status='active',
expires_at=timezone.now() + timezone.timedelta(days=3))
self.assertNotIn(402, self._every_route(self.paid))
self.assertEqual([u['requiresSubscription'] for u in self.client.get('/api/home').json()['units']],
[False, False])
sub.expires_at = timezone.now() - timezone.timedelta(minutes=1)
sub.save()
self.assertEqual(self.client.get(f'/api/nodes/{self.paid.id}/quiz').status_code, 402)
def test_status_reports_plan_title_and_quota(self):
from subscription.models import Plan
plan = Plan.objects.get(kind='subscription', on_sale=True, duration_days=90)
Subscription.objects.create(user_id=self.user.id, plan=plan, status='active',
expires_at=timezone.now() + timezone.timedelta(days=10))
body = self.client.get('/api/subscription/status').json()
self.assertEqual((body['active'], body['planTitle'], body['planDurationDays'], body['aiDailyQuota']),
(True, 'سه‌ماهه', 90, 3))