[BUILD-472] - Protect the chatbot feature based on plan availability (#2201)

[BUILD-472] - Protect the chatbot feature based on plan availability (#2201)

[BUILD-472] - Add the plan_feature_required decorator to the chatbot view, update tests.

diff --git a/ankihub/ai/tests/test_views.py b/ankihub/ai/tests/test_views.py
index 3b812be..4d31f0a 100644
--- a/ankihub/ai/tests/test_views.py
+++ b/ankihub/ai/tests/test_views.py
@@ -1086,6 +1086,7 @@ class TestUpdateModalDisplayUserSettingView:
 
 @pytest.mark.django_db
 @override_flag("chatbot", active=True)
+@override_flag("new_pricing_tier", active=True)
 @patch("ankihub.ai.views.uuid4")
 @patch("ankihub.ai.views.get_top_similarity_note_results_context")
 @patch("ankihub.ai.views.get_top_similarity_note_results")
@@ -1093,7 +1094,7 @@ def test_chatbot(
     mock_get_top_similarity_note_results,
     mock_get_top_similarity_note_results_context,
     mockuuid4,
-    user,
+    premium_user: User,
 ):
     corpus_value = "test"
     deck = DeckFactory()
@@ -1103,7 +1104,7 @@ def test_chatbot(
 
     uuid_value = "1234"
     mockuuid4.return_value = uuid_value
-    expected_chat_id = f"{user.id}-{uuid_value}"
+    expected_chat_id = f"{premium_user.id}-{uuid_value}"
 
     get_top_similarity_note_results_context_value = "context"
     mock_get_top_similarity_note_results.return_value = [note_embedding]
@@ -1113,13 +1114,17 @@ def test_chatbot(
 
     url = reverse("ai:chatbot", kwargs={"note_id": str(note.id)})
     client = Client()
-    client.force_login(user=user)
+    client.force_login(user=premium_user)
+
+    assert premium_user.has_perm("memberships.has_access", "reviewer_extension")
 
     response = client.get(url)
 
     mockuuid4.assert_called_once()
-    mock_get_top_similarity_note_results.assert_called_once_with(note, user)
-    mock_get_top_similarity_note_results_context.assert_called_once_with(note, user)
+    mock_get_top_similarity_note_results.assert_called_once_with(note, premium_user)
+    mock_get_top_similarity_note_results_context.assert_called_once_with(
+        note, premium_user
+    )
     assert response.status_code == 200
     assert "ai/chatbot.html" in (t.name for t in response.templates)
     assert response.context["note"] == note
@@ -1142,11 +1147,32 @@ def test_chatbot(
     )
 
 
-def test_chatbot_without_feature_flag_return_404(user):
+@override_flag("new_pricing_tier", active=True)
+def test_chatbot_trigger_upsell_users_with_no_access(free_user: User):
+    corpus_value = "test"
+    deck = DeckFactory()
+    note = NoteFactory.build(corpus=corpus_value, deck=deck)
+    note.save(skip_hooks=True)
+
+    url = reverse("ai:chatbot", kwargs={"note_id": str(note.id)})
+    client = Client()
+    client.force_login(user=free_user)
+
+    assert not free_user.has_perm("memberships.has_access", "reviewer_extension")
+
+    response = client.get(url)
+
+    assert response.status_code == 204
+
+
+@override_flag("new_pricing_tier", active=True)
+def test_chatbot_without_feature_flag_return_404(premium_user: User):
     note = NoteFactory()
     url = reverse("ai:chatbot", kwargs={"note_id": str(note.id)})
     client = Client()
-    client.force_login(user=user)
+    client.force_login(user=premium_user)
+
+    assert premium_user.has_perm("memberships.has_access", "reviewer_extension")
 
     response = client.get(url)
 
diff --git a/ankihub/ai/views.py b/ankihub/ai/views.py
index 5db0dbb..11586f7 100644
--- a/ankihub/ai/views.py
+++ b/ankihub/ai/views.py
@@ -490,6 +490,7 @@ def update_modal_display_user_setting(request):
 
 @knox_token_or_login_required
 @allow_embedding_on_localhost_only
+@plan_feature_required("reviewer_extension", show_dialog=True)
 def chatbot(request, note_id):
     if not flag_is_active(request, "chatbot"):
         raise Http404()

GitHub
sha: 4222409222442eb3a50f5f8936460befa2f00e28