Add setting to disable analytics

This commit is contained in:
Erik Kalkoken 2022-01-27 05:14:11 +00:00 committed by Ariel Rin
parent d8c6035405
commit ba39318313
6 changed files with 136 additions and 11 deletions

View File

@ -1,5 +1,6 @@
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
from .models import AnalyticsTokens, AnalyticsIdentifier from .models import AnalyticsTokens, AnalyticsIdentifier
from .tasks import send_ga_tracking_web_view from .tasks import send_ga_tracking_web_view
@ -10,6 +11,8 @@ import re
class AnalyticsMiddleware(MiddlewareMixin): class AnalyticsMiddleware(MiddlewareMixin):
def process_response(self, request, response): def process_response(self, request, response):
"""Django Middleware: Process Page Views and creates Analytics Celery Tasks""" """Django Middleware: Process Page Views and creates Analytics Celery Tasks"""
if getattr(settings, "ANALYTICS_DISABLED", False):
return response
analyticstokens = AnalyticsTokens.objects.all() analyticstokens = AnalyticsTokens.objects.all()
client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex
try: try:

View File

@ -1,7 +1,8 @@
from allianceauth.analytics.tasks import analytics_event
from celery.signals import task_failure, task_success
import logging import logging
from celery.signals import task_failure, task_success
from django.conf import settings
from allianceauth.analytics.tasks import analytics_event
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -11,6 +12,8 @@ def process_failure_signal(
sender, task_id, signal, sender, task_id, signal,
args, kwargs, einfo, **kw): args, kwargs, einfo, **kw):
logger.debug("Celery task_failure signal %s" % sender.__class__.__name__) logger.debug("Celery task_failure signal %s" % sender.__class__.__name__)
if getattr(settings, "ANALYTICS_DISABLED", False):
return
category = sender.__module__ category = sender.__module__
@ -30,6 +33,8 @@ def process_failure_signal(
@task_success.connect @task_success.connect
def celery_success_signal(sender, result=None, **kw): def celery_success_signal(sender, result=None, **kw):
logger.debug("Celery task_success signal %s" % sender.__class__.__name__) logger.debug("Celery task_success signal %s" % sender.__class__.__name__)
if getattr(settings, "ANALYTICS_DISABLED", False):
return
category = sender.__module__ category = sender.__module__

View File

@ -40,13 +40,12 @@ def analytics_event(category: str,
Send a Google Analytics Event for each token stored Send a Google Analytics Event for each token stored
Includes check for if its enabled/disabled Includes check for if its enabled/disabled
Parameters Args:
------- `category` (str): Celery Namespace
`category` (str): Celery Namespace `action` (str): Task Name
`action` (str): Task Name `label` (str): Optional, Task Success/Exception
`label` (str): Optional, Task Success/Exception `value` (int): Optional, If bulk, Query size, can be a binary True/False
`value` (int): Optional, If bulk, Query size, can be a binary True/False `event_type` (str): Optional, Celery or Stats only, Default to Celery
`event_type` (str): Optional, Celery or Stats only, Default to Celery
""" """
analyticstokens = AnalyticsTokens.objects.all() analyticstokens = AnalyticsTokens.objects.all()
client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex
@ -73,7 +72,8 @@ def analytics_event(category: str,
def analytics_daily_stats(): def analytics_daily_stats():
"""Celery Task: Do not call directly """Celery Task: Do not call directly
Gathers a series of daily statistics and sends analytics events containing them""" Gathers a series of daily statistics and sends analytics events containing them
"""
users = install_stat_users() users = install_stat_users()
tokens = install_stat_tokens() tokens = install_stat_tokens()
addons = install_stat_addons() addons = install_stat_addons()

View File

@ -0,0 +1,108 @@
from unittest.mock import patch
from urllib.parse import parse_qs
import requests_mock
from django.test import TestCase, override_settings
from allianceauth.analytics.tasks import ANALYTICS_URL
from allianceauth.eveonline.tasks import update_character
from allianceauth.tests.auth_utils import AuthUtils
@override_settings(CELERY_ALWAYS_EAGER=True)
@requests_mock.mock()
class TestAnalyticsForViews(TestCase):
@override_settings(ANALYTICS_DISABLED=False)
def test_should_run_analytics(self, requests_mocker):
# given
requests_mocker.post(ANALYTICS_URL)
user = AuthUtils.create_user("Bruce Wayne")
self.client.force_login(user)
# when
response = self.client.get("/dashboard/")
# then
self.assertEqual(response.status_code, 200)
self.assertTrue(requests_mocker.called)
@override_settings(ANALYTICS_DISABLED=True)
def test_should_not_run_analytics(self, requests_mocker):
# given
requests_mocker.post(ANALYTICS_URL)
user = AuthUtils.create_user("Bruce Wayne")
self.client.force_login(user)
# when
response = self.client.get("/dashboard/")
# then
self.assertEqual(response.status_code, 200)
self.assertFalse(requests_mocker.called)
@override_settings(CELERY_ALWAYS_EAGER=True)
@requests_mock.mock()
class TestAnalyticsForTasks(TestCase):
@override_settings(ANALYTICS_DISABLED=False)
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
def test_should_run_analytics_for_successful_task(
self, requests_mocker, mock_update_character
):
# given
requests_mocker.post(ANALYTICS_URL)
user = AuthUtils.create_user("Bruce Wayne")
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
# when
update_character.delay(character.character_id)
# then
self.assertTrue(mock_update_character.called)
self.assertTrue(requests_mocker.called)
payload = parse_qs(requests_mocker.last_request.text)
self.assertListEqual(payload["el"], ["Success"])
@override_settings(ANALYTICS_DISABLED=True)
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
def test_should_not_run_analytics_for_successful_task(
self, requests_mocker, mock_update_character
):
# given
requests_mocker.post(ANALYTICS_URL)
user = AuthUtils.create_user("Bruce Wayne")
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
# when
update_character.delay(character.character_id)
# then
self.assertTrue(mock_update_character.called)
self.assertFalse(requests_mocker.called)
@override_settings(ANALYTICS_DISABLED=False)
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
def test_should_run_analytics_for_failed_task(
self, requests_mocker, mock_update_character
):
# given
requests_mocker.post(ANALYTICS_URL)
mock_update_character.side_effect = RuntimeError
user = AuthUtils.create_user("Bruce Wayne")
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
# when
update_character.delay(character.character_id)
# then
self.assertTrue(mock_update_character.called)
self.assertTrue(requests_mocker.called)
payload = parse_qs(requests_mocker.last_request.text)
self.assertNotEqual(payload["el"], ["Success"])
@override_settings(ANALYTICS_DISABLED=True)
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
def test_should_not_run_analytics_for_failed_task(
self, requests_mocker, mock_update_character
):
# given
requests_mocker.post(ANALYTICS_URL)
mock_update_character.side_effect = RuntimeError
user = AuthUtils.create_user("Bruce Wayne")
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
# when
update_character.delay(character.character_id)
# then
self.assertTrue(mock_update_character.called)
self.assertFalse(requests_mocker.called)

View File

@ -42,6 +42,7 @@ from recommonmark.transform import AutoStructify
extensions = [ extensions = [
'sphinx_rtd_theme', 'sphinx_rtd_theme',
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'recommonmark', 'recommonmark',
] ]

View File

@ -10,6 +10,12 @@ To Opt-Out, modify our pre-loaded token using the Admin dashboard */admin/analyt
Each of the three features Daily Stats, Celery Events and Page Views can be enabled/Disabled independently. Each of the three features Daily Stats, Celery Events and Page Views can be enabled/Disabled independently.
Alternatively, you can fully opt out of analytics with the following optional setting:
```python
ANALYTICS_DISABLED = True
```
![Analytics Tokens](/_static/images/features/core/analytics/tokens.png) ![Analytics Tokens](/_static/images/features/core/analytics/tokens.png)
## What ## What
@ -58,6 +64,8 @@ This data is stored in a Team Google Analytics Dashboard. The Maintainers all ha
### Analytics Event ### Analytics Event
```eval_rst
.. automodule:: allianceauth.analytics.tasks .. automodule:: allianceauth.analytics.tasks
:members: analytics_event :members: analytics_event
:undoc-members: :undoc-members:
```