Skip to content

Commit

Permalink
Add ol-django olposthog app (#2211)
Browse files Browse the repository at this point in the history
* hold working

* update settings

* Update for rename

* Appears to be wroking

* Update more locations of is_enabled

* Better env var description

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Better env var description

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Updates

* Fix test, update app.json

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
collinpreston and pre-commit-ci[bot] authored May 16, 2024
1 parent ba41991 commit a7d1c8d
Show file tree
Hide file tree
Showing 18 changed files with 89 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SENTRY_DSN=
MITX_ONLINE_BASE_URL=http://mitxonline.odl.local:8013
MITX_ONLINE_ADMIN_CLIENT_ID=refine-local-client-id
MITX_ONLINE_ADMIN_BASE_URL=http://mitxonline.odl.local:8016
POSTHOG_API_TOKEN=
POSTHOG_PROJECT_API_KEY=
POSTHOG_API_HOST=https://app.posthog.com/
HUBSPOT_HOME_PAGE_FORM_GUID=
HUBSPOT_PORTAL_ID=
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
"filename": "main/settings.py",
"hashed_secret": "09edaaba587f94f60fbb5cee2234507bcb883cc2",
"is_verified": false,
"line_number": 954
"line_number": 958
}
],
"pants": [
Expand Down Expand Up @@ -247,5 +247,5 @@
}
]
},
"generated_at": "2024-05-13T13:11:36Z"
"generated_at": "2024-05-15T14:13:55Z"
}
14 changes: 13 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,19 @@
"description": "API host for PostHog",
"required": false
},
"POSTHOG_API_TOKEN": {
"POSTHOG_ENABLED": {
"description": "API host for PostHog",
"required": false
},
"POSTHOG_FEATURE_FLAG_REQUEST_TIMEOUT_MS": {
"description": "Timeout(MS) for PostHog feature flag requests.",
"required": false
},
"POSTHOG_MAX_RETRIES": {
"description": "Number of times that requests to PostHog should be retried after failing.",
"required": false
},
"POSTHOG_PROJECT_API_KEY": {
"description": "API token to communicate with PostHog",
"required": false
},
Expand Down
9 changes: 5 additions & 4 deletions cms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from django.utils.functional import cached_property
from django.utils.text import slugify
from mitol.common.utils.datetime import now_in_utc
from mitol.olposthog.features import is_enabled
from modelcluster.fields import ParentalKey
from wagtail.admin.panels import FieldPanel, InlinePanel, PageChooserPanel
from wagtail.blocks import PageChooserBlock, StreamBlock
Expand Down Expand Up @@ -826,22 +827,22 @@ def get_context(self, request, *args, **kwargs): # noqa: ARG002
request.session["anonymous_session_id"] = str(uuid.uuid4())
user = request.session["anonymous_session_id"]

show_new_featured_carousel = features.is_enabled(
show_new_featured_carousel = is_enabled(
features.ENABLE_NEW_HOME_PAGE_FEATURED,
False, # noqa: FBT003
user,
)
show_new_design_hero = features.is_enabled(
show_new_design_hero = is_enabled(
features.ENABLE_NEW_HOME_PAGE_HERO,
False, # noqa: FBT003
user,
)
show_home_page_video_component = features.is_enabled(
show_home_page_video_component = is_enabled(
features.ENABLE_NEW_HOME_PAGE_VIDEO,
False, # noqa: FBT003
user,
)
show_home_page_contact_form = features.is_enabled(
show_home_page_contact_form = is_enabled(
features.ENABLE_NEW_HOME_PAGE_CONTACT_FORM,
False, # noqa: FBT003
user,
Expand Down
11 changes: 7 additions & 4 deletions cms/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.urls import resolve
from mitol.common.factories import UserFactory
from mitol.common.utils.datetime import now_in_utc
from mitol.olposthog.features import is_enabled

from cms.constants import CMS_EDITORS_GROUP_NAME
from cms.factories import (
Expand Down Expand Up @@ -44,7 +45,6 @@
from flexiblepricing.constants import FlexiblePriceStatus
from flexiblepricing.factories import FlexiblePriceFactory, FlexiblePriceTierFactory
from flexiblepricing.models import FlexiblePrice
from main import features

pytestmark = [pytest.mark.django_db]

Expand All @@ -57,7 +57,10 @@ def test_resource_page_site_name(settings, mocker):
"""
settings.SITE_NAME = "a site's name"
page = ResourcePageFactory.create()
assert page.get_context(mocker.Mock())["site_name"] == settings.SITE_NAME
rf = RequestFactory()
request = rf.get("/")
mocker.patch("cms.models.get_base_context")
assert page.get_context(request)["site_name"] == settings.SITE_NAME


def test_custom_detail_page_urls(fully_configured_wagtail):
Expand Down Expand Up @@ -168,12 +171,12 @@ def test_course_page_context( # noqa: PLR0913
member.linked_instructor_page
for member in course_page.linked_instructors.order_by("order").all()
],
"new_design": features.is_enabled(
"new_design": is_enabled(
"mitxonline-new-product-page",
False, # noqa: FBT003
request.user.id if request.user.is_authenticated else "anonymousUser",
),
"new_footer": features.is_enabled(
"new_footer": is_enabled(
"mitxonline-new-footer",
False, # noqa: FBT003
request.user.id if request.user.is_authenticated else "anonymousUser",
Expand Down
3 changes: 2 additions & 1 deletion courses/serializers/v1/courses.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from mitol.olposthog.features import is_enabled
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

Expand Down Expand Up @@ -146,7 +147,7 @@ def create(self, validated_data):
successful_enrollments, edx_request_success = create_run_enrollments(
user,
[run],
keep_failed_enrollments=features.is_enabled(features.IGNORE_EDX_FAILURES),
keep_failed_enrollments=is_enabled(features.IGNORE_EDX_FAILURES),
)
return successful_enrollments

Expand Down
3 changes: 2 additions & 1 deletion courses/serializers/v2/courses.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging

from mitol.olposthog.features import is_enabled
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

Expand Down Expand Up @@ -158,7 +159,7 @@ def create(self, validated_data):
successful_enrollments, edx_request_success = create_run_enrollments(
user,
[run],
keep_failed_enrollments=features.is_enabled(features.IGNORE_EDX_FAILURES),
keep_failed_enrollments=is_enabled(features.IGNORE_EDX_FAILURES),
)
return successful_enrollments

Expand Down
9 changes: 5 additions & 4 deletions courses/views/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django_filters.rest_framework import DjangoFilterBackend
from mitol.olposthog.features import is_enabled
from requests import ConnectionError as RequestsConnectionError
from requests.exceptions import HTTPError
from rest_framework import mixins, status, viewsets
Expand Down Expand Up @@ -277,7 +278,7 @@ def create_enrollment_view(request):
_, edx_request_success = create_run_enrollments(
user=user,
runs=[run],
keep_failed_enrollments=features.is_enabled(features.IGNORE_EDX_FAILURES),
keep_failed_enrollments=is_enabled(features.IGNORE_EDX_FAILURES),
)

def respond(data, status=True): # noqa: FBT002
Expand All @@ -290,7 +291,7 @@ def respond(data, status=True): # noqa: FBT002

return HttpResponseRedirect(data)

if edx_request_success or features.is_enabled(features.IGNORE_EDX_FAILURES):
if edx_request_success or is_enabled(features.IGNORE_EDX_FAILURES):
resp = respond(reverse("user-dashboard"))
cookie_value = {
"type": USER_MSG_TYPE_ENROLLED,
Expand Down Expand Up @@ -362,7 +363,7 @@ def get_serializer_context(self):
return {"user": self.request.user}

def list(self, request, *args, **kwargs):
if features.is_enabled(features.SYNC_ON_DASHBOARD_LOAD):
if is_enabled(features.SYNC_ON_DASHBOARD_LOAD):
try:
sync_enrollments_with_edx(self.request.user)
except Exception: # pylint: disable=broad-except
Expand All @@ -374,7 +375,7 @@ def destroy(self, request, *args, **kwargs): # noqa: ARG002
deactivated_enrollment = deactivate_run_enrollment(
enrollment,
change_status=ENROLL_CHANGE_STATUS_UNENROLLED,
keep_failed_enrollments=features.is_enabled(features.IGNORE_EDX_FAILURES),
keep_failed_enrollments=is_enabled(features.IGNORE_EDX_FAILURES),
)
if deactivated_enrollment is None:
return Response(status=status.HTTP_400_BAD_REQUEST)
Expand Down
1 change: 1 addition & 0 deletions courses/views/v1/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ def test_user_enrollments_list_sync(
If the appropriate feature flag is turned on, the enrollments list API call should sync enrollments with
"""
settings.FEATURES[features.SYNC_ON_DASHBOARD_LOAD] = sync_dashboard_flag
settings.POSTHOG_ENABLED = False
patched_sync = mocker.patch(
"courses.views.v1.sync_enrollments_with_edx",
)
Expand Down
2 changes: 2 additions & 0 deletions main/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ class RootConfig(AppConfig):

def ready(self):
from mitol.common import envs
from mitol.olposthog.features import configure

envs.validate()
configure()
63 changes: 0 additions & 63 deletions main/features.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
"""MITxOnline feature flags"""

import os
from functools import wraps

from django.conf import settings

IGNORE_EDX_FAILURES = "IGNORE_EDX_FAILURES"
SYNC_ON_DASHBOARD_LOAD = "SYNC_ON_DASHBOARD_LOAD"
ENABLE_NEW_DESIGN = "mitxonline-new-product-page"
Expand All @@ -15,61 +10,3 @@
ENABLE_NEW_HOME_PAGE_CONTACT_FORM = "mitxonline-new-home-page-contact-form"
ENABLE_NEW_FOOTER = "mitxonline-new-footer"
ENABLE_AUTO_DAILY_FEATURED_ITEMS = "mitxonline-auto-daily-featured-items"


def is_enabled(name, default=None, unique_id=settings.HOSTNAME):
"""
Returns True if the feature flag is enabled
Args:
name (str): feature flag name
default (bool): default value if not set in settings
unique_id (str): person identifier passed back to posthog which is the display value for person. I recommend
this be user.id for logged-in users to allow for more readable user flags as well as more clear
troubleshooting. For anonymous users, a persistent ID will help with troubleshooting and
tracking efforts.
Returns:
bool: True if the feature flag is enabled
"""

if "IN_TEST_SUITE" not in os.environ:
import posthog
else:
posthog = None
return (
posthog
and posthog.get_feature_flag(
name,
unique_id,
person_properties={
"environment": settings.ENVIRONMENT,
"user_id": unique_id,
},
)
) or settings.FEATURES.get(name, default or settings.FEATURES_DEFAULT)


def if_feature_enabled(name, default=None):
"""
Wrapper that results in a no-op if the given feature isn't enabled, and otherwise
runs the wrapped function as normal.
Args:
name (str): Feature flag name
default (bool): default value if not set in settings
"""

def if_feature_enabled_inner(func): # pylint: disable=missing-docstring
@wraps(func)
def wrapped_func(*args, **kwargs): # pylint: disable=missing-docstring
if not is_enabled(name, default):
# If the given feature name is not enabled, do nothing (no-op).
return None
else:
# If the given feature name is enabled, call the function and return as normal.
return func(*args, **kwargs)

return wrapped_func

return if_feature_enabled_inner
30 changes: 24 additions & 6 deletions main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import cssutils
import dj_database_url
import posthog
from celery.schedules import crontab
from django.core.exceptions import ImproperlyConfigured
from mitol.common.envs import (
Expand Down Expand Up @@ -217,6 +216,7 @@
"mitol.mail.apps.MailApp",
"mitol.authentication.apps.TransitionalAuthenticationApp",
"mitol.payment_gateway.apps.PaymentGatewayApp",
"mitol.olposthog.apps.OlPosthog",
# "mitol.oauth_toolkit_extensions.apps.OAuthToolkitExtensionsApp",
)
# Only include the seed data app if this isn't running in prod
Expand Down Expand Up @@ -896,6 +896,10 @@
"LOCATION": CELERY_BROKER_URL,
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
},
"durable": {
"BACKEND": "django.core.cache.backends.db.DatabaseCache",
"LOCATION": "durable_cache",
},
}

AUTHENTICATION_BACKENDS = (
Expand Down Expand Up @@ -1153,8 +1157,8 @@
)

# PostHog related settings
POSTHOG_API_TOKEN = get_string(
name="POSTHOG_API_TOKEN",
POSTHOG_PROJECT_API_KEY = get_string(
name="POSTHOG_PROJECT_API_KEY",
default="",
description="API token to communicate with PostHog",
)
Expand All @@ -1164,9 +1168,23 @@
default="",
description="API host for PostHog",
)
if "IN_TEST_SUITE" not in os.environ:
posthog.api_key = POSTHOG_API_TOKEN
posthog.host = POSTHOG_API_HOST
POSTHOG_FEATURE_FLAG_REQUEST_TIMEOUT_MS = get_int(
name="POSTHOG_FEATURE_FLAG_REQUEST_TIMEOUT_MS",
default=3000,
description="Timeout(MS) for PostHog feature flag requests.",
)

POSTHOG_MAX_RETRIES = get_int(
name="POSTHOG_MAX_RETRIES",
default=3,
description="Number of times that requests to PostHog should be retried after failing.",
)

POSTHOG_ENABLED = get_bool(
name="POSTHOG_ENABLED",
default=False,
description="API host for PostHog",
)

# HomePage Hubspot Form Settings
HUBSPOT_HOME_PAGE_FORM_GUID = get_string(
Expand Down
2 changes: 1 addition & 1 deletion main/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def get_js_settings(request: HttpRequest): # noqa: ARG001
"support_email": settings.EMAIL_SUPPORT,
"site_name": settings.SITE_NAME,
"features": {},
"posthog_api_token": settings.POSTHOG_API_TOKEN,
"posthog_api_token": settings.POSTHOG_PROJECT_API_KEY,
"posthog_api_host": settings.POSTHOG_API_HOST,
}

Expand Down
2 changes: 1 addition & 1 deletion main/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_get_js_settings(settings, rf):
"support_email": settings.EMAIL_SUPPORT,
"site_name": settings.SITE_NAME,
"features": {},
"posthog_api_token": settings.POSTHOG_API_TOKEN,
"posthog_api_token": settings.POSTHOG_PROJECT_API_KEY,
"posthog_api_host": settings.POSTHOG_API_HOST,
}

Expand Down
5 changes: 3 additions & 2 deletions main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.template.loader import render_to_string
from django.urls import reverse
from django.views.decorators.cache import never_cache
from mitol.olposthog.features import is_enabled
from rest_framework.pagination import LimitOffsetPagination

from main import features
Expand All @@ -19,12 +20,12 @@ def get_base_context(request):
Returns the template context key/values needed for the base template and all templates that extend it
"""
context = {
"new_design": features.is_enabled(
"new_design": is_enabled(
features.ENABLE_NEW_DESIGN,
False, # noqa: FBT003
request.user.id if request.user.is_authenticated else "anonymousUser",
),
"new_footer": features.is_enabled(
"new_footer": is_enabled(
features.ENABLE_NEW_FOOTER,
False, # noqa: FBT003
request.user.id if request.user.is_authenticated else "anonymousUser",
Expand Down
Loading

0 comments on commit a7d1c8d

Please sign in to comment.