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>
This commit is contained in:
70
content/tests_paywall.py
Normal file
70
content/tests_paywall.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
فصلِ اولِ هر پایه رایگان است و بقیه اشتراکِ زمانی میخواهند (۲۰۲۶-۱۰-۱۰).
|
||||
بازیکردنِ فصلِ قفل از هر مسیری (سوالهای درس، آزمونِ جزیره، جواب، پایانِ درس/جزیره) ۴۰۲ میگیرد.
|
||||
"""
|
||||
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))
|
||||
Reference in New Issue
Block a user