Repository: mitodl/ocw-studio
Pull request #2445: env variables for MIT Learn in theme assets pipeline
Author: login: gumaerc
Labels: name: Needs Review
Created: 2025-03-11T02:09:48Z | Merged: 2025-03-19T16:02:22Z

### What are the relevant tickets?
Closes https://github.com/mitodl/ocw-studio/issues/2444

### Description (What does it do?)
This PR adds some environment variables to the theme assets pipeline for both Posthog support as well as supporting the MIT Learn integration functionality

### How can this be tested?
 - Ensure you have a Posthog API key
 - In your `.env` in `ocw-studio`, make sure you have:
```
OCW_HUGO_THEMES_BRANCH=cg/add-login-button
OCW_HUGO_PROJECTS_BRANCH=main

POSTHOG_PROJECT_API_KEY=YOUR_API_KEY_HERE
POSTHOG_ENABLED=true

MIT_LEARN_BASE_URL=https://rc.learn.mit.edu
MIT_LEARN_API_BASE_URL=https://api.rc.learn.mit.edu
```
 - Spin up `ocw-studio`
 - Run `docker compose exec web ./manage.py upsert_theme_assets_pipeline --themes-branch cg/add-login-button`
 - Browse to Concourse at http://localhost:8080/ and log in
 - Find the theme assets pipeline for the branch we specified, unpause the pipeline and run it
 - Ensure that the pipeline completes successfully
 - Upsert the pipeline for any site by using the `backpopulate_pipelines` management command with the `--filter` argument to specify which site
 - Publish the site
 - View the site and open the developer console
 - Ensure that you see a "Posthog loaded successfully" message
 - Ensure you see a "Log In" button in the upper right
 - Click the "Log In" button and you should be redirected to RC Learn
 
 We don't need to test actually using the login button, that will come later. The purpose of this PR is just to make certain that the proper values are being injected into the bundle.



Diff:
diff --git a/app.json b/app.json
index 8ae453998..063ca8aa0 100644
--- a/app.json
+++ b/app.json
@@ -98,6 +98,14 @@
       "description": "Early executed tasks propagate exceptions",
       "required": false
     },
+    "CHECK_EXTERNAL_RESOURCE_STATUS_FREQUENCY": {
+      "description": "Frequency (in seconds) to check potentially broken external urls",
+      "required": false
+    },
+    "CHECK_EXTERNAL_RESOURCE_TASK_STATUS": {
+      "description": "Enables celery task to check potentially broken external urls",
+      "required": false
+    },
     "CONCOURSE_HARD_PURGE": {
       "description": "Perform a hard purge of the fastly cache",
       "required": false
@@ -122,6 +130,10 @@
       "description": "The concourse-ci login username",
       "required": false
     },
+    "CONTENT_FILE_SEARCH_API_URL": {
+      "description": "The URL to open discussions content file search to inject into the theme assets build",
+      "required": false
+    },
     "CONTENT_SYNC_BACKEND": {
       "description": "The backend to sync websites/content with",
       "required": false
@@ -134,6 +146,10 @@
       "description": "Number of times to retry backend sync attempts",
       "required": false
     },
+    "COURSE_SEARCH_API_URL": {
+      "description": "The URL to open discussions learning resource search to inject into the theme assets build",
+      "required": false
+    },
     "DISABLE_WEBPACK_LOADER_STATS": {
       "description": "Disabled webpack loader stats",
       "required": false
@@ -158,24 +174,12 @@
       "description": "Gdrive folder for video uploads",
       "required": false
     },
-    "ENV_NAME": {
-      "description": "Name of environment from Heroku or other deployment",
-      "required": false
-    },
-    "FEATURE_SORTABLE_SELECT_PRESERVE_SEARCH_TEXT": {
-      "description": "Feature flag sortable select preserves search text",
-      "required": false
-    },
-    "FEATURE_SORTABLE_SELECT_HIDE_SELECTED": {
-      "description": "Feature flag sortable select hides selected items",
-      "required": false
-    },
-    "FEATURE_SORTABLE_SELECT_QUICK_ADD": {
-      "description": "Feature flag sortable select adds item on selection",
+    "ENABLE_WAYBACK_TASKS": {
+      "description": "Enables tasks related to Wayback Machine submissions and status checks",
       "required": false
     },
-    "FEATURE_SELECT_FIELD_INFINITE_SCROLL": {
-      "description": "Feature flag select field allows infinite scroll",
+    "ENV_NAME": {
+      "description": "Name of environment from Heroku or other deployment",
       "required": false
     },
     "FIELD_METADATA_TITLE": {
@@ -302,6 +306,14 @@
       "description": "E-mail to use for reply-to address of emails",
       "required": false
     },
+    "MIT_LEARN_API_BASE_URL": {
+      "description": "URL to an instance of the MIT Learn API",
+      "required": false
+    },
+    "MIT_LEARN_BASE_URL": {
+      "description": "URL to an instance of MIT Learn",
+      "required": false
+    },
     "NEW_RELIC_APP_NAME": {
       "description": "Application identifier in New Relic."
     },
@@ -333,10 +345,6 @@
       "description": "The amount of sites to build simultaneously in each job created by MassBuildSitesPipelineDefinition",
       "required": false
     },
-    "OPEN_CATALOG_WEBHOOK_KEY": {
-      "description": "Open catalog webhook key",
-      "required": false
-    },
     "OCW_STUDIO_ADMIN_EMAIL": {
       "description": "E-mail to send 500 reports to.",
       "required": false
@@ -429,20 +437,20 @@
       "description": "Email address listed for customer support",
       "required": false
     },
-    "OCW_STUDIO_USE_S3": {
-      "description": "Use S3 for storage backend (required on Heroku)",
+    "OCW_STUDIO_TEST_URL": {
+      "description": "The base url of the test site",
       "required": false
     },
-    "OCW_TEST_COURSE_STARTER_SLUG": {
-      "description": "The slug of the course Website used to run end to end tests",
+    "OCW_STUDIO_USE_S3": {
+      "description": "Use S3 for storage backend (required on Heroku)",
       "required": false
     },
-    "OCW_TEST_WWW_STARTER_SLUG": {
-      "description": "The slug of the root Website used to run end to end tests",
+    "OPEN_CATALOG_URLS": {
+      "description": "Open catalog urls",
       "required": false
     },
-    "OPEN_CATALOG_URLS": {
-      "description": "List of open catalog urls",
+    "OPEN_CATALOG_WEBHOOK_KEY": {
+      "description": "Open discussions webhook key",
       "required": false
     },
     "PGBOUNCER_DEFAULT_POOL_SIZE": {
@@ -463,6 +471,10 @@
       "description": "Timeout (ms) for PostHog feature flag requests",
       "required": false
     },
+    "POSTHOG_MAX_RETRIES": {
+      "description": "Number of times requests to PostHog are retried if failed",
+      "required": false
+    },
     "POSTHOG_PROJECT_API_KEY": {
       "description": "API token for communicating with PostHog",
       "required": false
@@ -515,14 +527,6 @@
       "description": "The URL to open discussions search to inject into the theme assets build",
       "required": false
     },
-    "COURSE_SEARCH_API_URL": {
-      "description": "The URL to open discussions learning resource search to inject into the theme assets build",
-      "required": false
-    },
-    "CONTENT_FILE_SEARCH_API_URL": {
-      "description": "The URL to open discussions content file search to inject into the theme assets build",
-      "required": false
-    },
     "SECRET_KEY": {
       "description": "Django secret key.",
       "generator": "secret",
@@ -604,6 +608,10 @@
       "description": "Token to access the status API.",
       "required": false
     },
+    "TEST_ROOT_WEBSITE_NAME": {
+      "description": "The Website name for the site at the root of the test domain",
+      "required": false
+    },
     "THREEPLAY_API_KEY": {
       "description": "3play api key",
       "required": false
@@ -624,6 +632,10 @@
       "description": "The frequency to check for videos tagged as updated in 3play",
       "required": false
     },
+    "UPDATE_WAYBACK_JOBS_STATUS_FREQUENCY": {
+      "description": "Frequency (in seconds) to check the status of Wayback Machine jobs",
+      "required": false
+    },
     "USE_X_FORWARDED_HOST": {
       "description": "Set HOST header to original domain accessed by user",
       "required": false
@@ -652,17 +664,8 @@
       "description": "Secret key for the Wayback Machine API",
       "required": false
     },
-    "UPDATE_WAYBACK_JOBS_STATUS_FREQUENCY": {
-      "description": "Frequency (in seconds) to check the status of Wayback Machine jobs",
-      "required": false
-    },
     "WAYBACK_SUBMISSION_INTERVAL_DAYS": {
       "description": "Number of days between Wayback submissions",
-      "required": false,
-      "value": "30"
-    },
-    "ENABLE_WAYBACK_TASKS": {
-      "description": "Enables tasks related to Wayback Machine submissions and status checks",
       "required": false
     },
     "YT_ACCESS_TOKEN": {
diff --git a/content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py b/content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py
index ec58fae22..e5eb38151 100644
--- a/content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py
+++ b/content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py
@@ -101,6 +101,8 @@ def __init__(  # noqa: PLR0913
                         "POSTHOG_ENV": settings.ENVIRONMENT,
                         "SENTRY_DSN": settings.OCW_HUGO_THEMES_SENTRY_DSN,
                         "SENTRY_ENV": settings.ENVIRONMENT,
+                        "MIT_LEARN_BASE_URL": settings.MIT_LEARN_BASE_URL,
+                        "MIT_LEARN_API_BASE_URL": settings.MIT_LEARN_API_BASE_URL,
                     },
                     run=Command(
                         path="sh",
diff --git a/content_sync/serializers.py b/content_sync/serializers.py
index 7c489b93c..b022bec00 100644
--- a/content_sync/serializers.py
+++ b/content_sync/serializers.py
@@ -3,6 +3,7 @@
 import abc
 import json
 import re
+from pathlib import Path
 from typing import Optional
 from urllib.parse import urlparse
 
@@ -70,11 +71,17 @@ class HugoMarkdownFileSerializer(BaseContentFileSerializer):
     """Serializer/deserializer class for Hugo Markdown content and files"""
 
     def serialize(self, website_content: WebsiteContent) -> str:
+        file_path = Path(
+            "/",
+            website_content.website.get_url_path(),
+            Path(website_content.file.name).name,
+        )
         front_matter = {
             **(website_content.full_metadata or {}),
             "uid": website_content.text_id,
             "title": website_content.title,
             "content_type": website_content.type,
+            "file": file_path.as_posix(),
         }
         # NOTE: yaml.dump adds a newline to the end of its output by default
         return f"---\n{yaml.dump(front_matter)}---\n{website_content.markdown or ''}"
diff --git a/content_sync/serializers_test.py b/content_sync/serializers_test.py
index 01b317f2d..73aabe28c 100644
--- a/content_sync/serializers_test.py
+++ b/content_sync/serializers_test.py
@@ -2,6 +2,7 @@
 
 import json
 import re
+from pathlib import Path
 
 import pytest
 import yaml
@@ -122,6 +123,7 @@ def test_hugo_file_serialize(settings, markdown, exp_sections):
         file=SimpleUploadedFile("mysite/test.pdf", b"content"),
         website=WebsiteFactory.create(name="mysite", url_path="sites/mysite-fall-2025"),
     )
+    file_path = Path("/", content.website.get_url_path(), Path(content.file.name).name)
     site_config = SiteConfig(content.website.starter.config)
 
     file_content = HugoMarkdownFileSerializer(site_config).serialize(
@@ -142,6 +144,7 @@ def test_hugo_file_serialize(settings, markdown, exp_sections):
             f"title: {content.title}",
             f"content_type: {content.type}",
             f"uid: {content.text_id}",
+            f"file: {file_path}",
         ]
         + [f"{k}: {v}" for k, v in metadata.items()]
     )
diff --git a/main/settings.py b/main/settings.py
index 11115ef6e..a593b075d 100644
--- a/main/settings.py
+++ b/main/settings.py
@@ -1312,3 +1312,15 @@
     default=[],
     description="List of content types that can be deleted",
 )
+MIT_LEARN_BASE_URL = get_string(
+    name="MIT_LEARN_BASE_URL",
+    default=None,
+    description="URL to an instance of MIT Learn",
+    required=False,
+)
+MIT_LEARN_API_BASE_URL = get_string(
+    name="MIT_LEARN_API_BASE_URL",
+    default=None,
+    description="URL to an instance of the MIT Learn API",
+    required=False,
+)
diff --git a/websites/views.py b/websites/views.py
index e563aef8b..2b6745a2e 100644
--- a/websites/views.py
+++ b/websites/views.py
@@ -326,10 +326,12 @@ def pipeline_status(self, request, name=None):
     def hide_download(self, request, name=None):  # noqa: ARG002
         """Process webhook requests from concourse pipeline runs"""
         website = get_object_or_404(Website, name=name)
-        content = WebsiteContent.objects.get(
-            website=website, type=CONTENT_TYPE_METADATA
-        )
-        hide_download = content and content.metadata.get("hide_download")
+        hide_download = False
+        if website.name != settings.ROOT_WEBSITE_NAME:
+            content = WebsiteContent.objects.get(
+                website=website, type=CONTENT_TYPE_METADATA
+            )
+            hide_download = content and content.metadata.get("hide_download")
         return Response(
             status=200,
             data={} if hide_download else {"version": str(now_in_utc().timestamp())},


Reviews:
user: login: gemini-code-assist[bot]
body: Hello @gumaerc, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

## Summary of Changes
This pull request introduces environment variables to the theme assets pipeline for Posthog and MIT Learn integration. It modifies the `app.json` file to define new environment variables and updates the `theme_assets_pipeline.py` file to inject these variables into the theme assets build process. Additionally, it adds a `file` attribute to the front matter of Hugo Markdown files in `content_sync/serializers.py` and defines new settings for MIT Learn URLs in `main/settings.py`.

### Highlights
* **Environment Variables**: New environment variables are added to `app.json` for Posthog (e.g., `POSTHOG_PROJECT_API_KEY`, `POSTHOG_ENABLED`) and MIT Learn (e.g., `MIT_LEARN_BASE_URL`, `MIT_LEARN_API_BASE_URL`).
* **Theme Assets Pipeline**: The `theme_assets_pipeline.py` file is updated to inject the new environment variables into the theme assets build process, enabling Posthog and MIT Learn functionality in the themes.
* **Hugo Markdown Serializer**: The `HugoMarkdownFileSerializer` in `content_sync/serializers.py` is modified to include a `file` attribute in the front matter, representing the file path of the content.
* **Settings**: New settings are added to `main/settings.py` to define the base URLs for MIT Learn and its API.

### Changelog
<details>
<summary>Click here to see the changelog</summary>

* **app.json**
  * Added new environment variables for Posthog: `CHECK_EXTERNAL_RESOURCE_STATUS_FREQUENCY` (line 101), `CHECK_EXTERNAL_RESOURCE_TASK_STATUS` (line 105), `POSTHOG_MAX_RETRIES` (line 474), `POSTHOG_PROJECT_API_KEY` (line 478), `POSTHOG_TIMEOUT_MS` (line 471)
  * Added new environment variables for MIT Learn: `MIT_LEARN_API_BASE_URL` (line 309), `MIT_LEARN_BASE_URL` (line 313)
  * Added new environment variables for content file search and course search: `CONTENT_FILE_SEARCH_API_URL` (line 133), `COURSE_SEARCH_API_URL` (line 149)
  * Removed some feature flags and reordered some entries
  * Added `OCW_STUDIO_TEST_URL` (line 440) and `TEST_ROOT_WEBSITE_NAME` (line 611)
  * Added `UPDATE_WAYBACK_JOBS_STATUS_FREQUENCY` (line 635)
* **content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py**
  * Injected `POSTHOG_ENABLED`, `POSTHOG_PROJECT_API_KEY`, `MIT_LEARN_BASE_URL`, and `MIT_LEARN_API_BASE_URL` environment variables into the theme assets build process (lines 100-103).
* **content_sync/serializers.py**
  * Added a `file` attribute to the front matter of Hugo Markdown files, representing the file path (lines 74-76, 82).
* **main/settings.py**
  * Added settings for `MIT_LEARN_BASE_URL` (line 1315) and `MIT_LEARN_API_BASE_URL` (line 1321).

</details>


<details>

<summary><b>Using Gemini Code Assist</b></summary>
<br>

The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips.

<b>Invoking Gemini</b>

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either `/gemini <command>` or `@gemini-code-assist <command>`. Below is a summary of the supported commands.

Feature | Command | Description
--- | --- | ---
Code Review | `/gemini review` | Performs a code review for the current pull request in its current state.
Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state.
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments.
Help | `/gemini help` | Displays a list of available commands.

<b>Customization</b>

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a `.gemini/` folder in the base of the repository. Detailed instructions can be found [here](https://developers.google.com/gemini-code-assist/docs/review-github-code).

<b>Limitations & Feedback</b>

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments to provide feedback.

</details>

<b>You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the [Gemini Code Assist IDE Extension](https://cloud.google.com/products/gemini/code-assist).</b>


[^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/review-github-code). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).

---

**Trivia time!**

What is PostHog?

<details>
<summary><b>Click here for the answer</b></summary>
<br>
PostHog is an open-source product analytics platform that helps developers understand user behavior, track events, and automate user research.

</details>

state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T02:09:58Z
user: login: gemini-code-assist[bot]
body: ## Code Review
This pull request introduces environment variables for Posthog and MIT Learn in the theme assets pipeline. The changes look good overall, but there are a few areas that could be improved for clarity and consistency.

### Summary of Findings
* **Inconsistent 'required' field values in app.json**: The 'required' field in app.json has inconsistent string values ('False' vs 'false'). It should be standardized to a boolean value (false) for consistency.
* **Duplicated environment variable descriptions in app.json**: The descriptions for CONTENT_FILE_SEARCH_API_URL and COURSE_SEARCH_API_URL are duplicated in app.json. The original entries should be removed to avoid confusion.
* **Hardcoded 'true' value for POSTHOG_ENABLED**: The POSTHOG_ENABLED variable is hardcoded to 'true' in theme_assets_pipeline.py. It should be dynamically set based on the settings value.

### Merge Readiness
The pull request is almost ready for merging. However, the inconsistencies in the `required` field values in `app.json` and the hardcoded `POSTHOG_ENABLED` value should be addressed first. I am unable to approve this pull request, and recommend that others review and approve this code before merging.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T02:10:27Z
user: login: ibrahimjaved12
body: After initializing the `ocw-learn-integration` feature flag in PostHog, and running an instance of Chrome with CORS disabled, it worked for me.

<img width="1440" alt="image" src="https://github.com/user-attachments/assets/7e7b1c63-f77c-4e8b-b970-b8b569122792" />

<img width="1438" alt="image" src="https://github.com/user-attachments/assets/bd3efc9d-0907-447d-a150-3b87cd136dac" />



LGTM 👍🏻
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T08:18:18Z

Review comments:
diff_hunk: @@ -97,6 +97,10 @@ def __init__(  # noqa: PLR0913
                         "CONTENT_FILE_SEARCH_API_URL": settings.CONTENT_FILE_SEARCH_API_URL,  # noqa:E501
                         "SENTRY_DSN": settings.OCW_HUGO_THEMES_SENTRY_DSN,
                         "SENTRY_ENV": settings.ENVIRONMENT,
+                        "POSTHOG_ENABLED": "true",
path: content_sync/pipelines/definitions/concourse/theme_assets_pipeline.py
user: login: gemini-code-assist[bot]
body: ![high](https://img.shields.io/badge/priority-high-orange)

Instead of hardcoding `"true"`, use the actual boolean value of the setting and let the Hugo templating engine handle the conversion to a string. This makes the code more maintainable and less prone to errors if the setting type changes in the future.

```suggestion
                        "POSTHOG_ENABLED": settings.POSTHOG_ENABLED,
```
created_at: 2025-03-11T02:10:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -302,6 +306,14 @@
       "description": "E-mail to use for reply-to address of emails",
       "required": false
     },
+    "MIT_LEARN_API_BASE_URL": {
+      "description": "URL to an instance of the MIT Learn API",
+      "required": "False"
path: app.json
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

For consistency, the `required` field should be a boolean value (`false`) instead of a string (`"False"`).

```
      "required": false
```
created_at: 2025-03-11T02:10:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -302,6 +306,14 @@
       "description": "E-mail to use for reply-to address of emails",
       "required": false
     },
+    "MIT_LEARN_API_BASE_URL": {
+      "description": "URL to an instance of the MIT Learn API",
+      "required": "False"
+    },
+    "MIT_LEARN_BASE_URL": {
+      "description": "URL to an instance of MIT Learn",
+      "required": "False"
path: app.json
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

For consistency, the `required` field should be a boolean value (`false`) instead of a string (`"False"`).

```
      "required": false
```
created_at: 2025-03-11T02:10:27Z
author_association: CONTRIBUTOR

PR comments:
user: login: ibrahimjaved12
created_at: 2025-03-18T11:55:46Z
body: @gumaerc 

I got the `Posthog loaded successfully` message in console but not able to get the login button in the top-right.
<img width="1432" alt="image" src="https://github.com/user-attachments/assets/34e34f73-c12a-4191-92a3-9064dbad6125" />


Using the correct `ocw-hugo-themes` branch:
<img width="882" alt="image" src="https://github.com/user-attachments/assets/dea397ce-f074-44f9-bba6-6069c207a92b" />

Not getting the button in ocw-www either, which was shown here: https://github.com/mitodl/ocw-hugo-themes/pull/1544

I checked out to the `cg/add-login-button` branch in `ocw-hugo-themes`, used the Posthog variables in .env, got `Posthog loaded successfully` in console, but didn't see the login button there as well.

Looking into the code,
`if (userMenuContainers && isFeatureEnabled("ocw-learn-integration")) {
`
I don't see the feature flag `ocw-learn-integration` in the PostHog interface under OCW or MIT Learn projects. Does it need to be created? Or are my `.env` values problematic? I'm using the same value for `POSTHOG_PROJECT_API_KEY` present in OCW project -- which I had also used to test other PostHog feature flags in Studio.

Also, I tried to remove the if check locally from the code, to see if that would make the login appear, but it didn't:
`if (userMenuContainers && isFeatureEnabled("ocw-learn-integration")) {
`
author_association: CONTRIBUTOR
user: login: gumaerc
created_at: 2025-03-18T21:19:20Z
body: @ibrahimjaved12 I tested this out again today and it does seem to be working for me, but I was reminded of something with Posthog that you might be experiencing. Since we're currently using the default posthog domain (app.posthog.com), if you have an ad blocker on then calls to Posthog will fail. I believe it will still initialize properly, but actual calls to the API will fail. Check that you do not have an ad blocker enabled and give it another shot.

As far as the feature flag itself, I neglected to mention in the testing instructions that when I do testing for this I simply use my own test project in Posthog, not tied to any of the ones ODL owns. That way, I can set arbitrary feature flags for testing without them having to be mixed in with ones we actually use in RC and production. I planned to add the feature flag to the MIT projects once this PR merges and I go to test in RC. You can see an example of how it's supposed to function here: https://ocw.c4103.com/courses/18-s096-matrix-calculus-for-machine-learning-and-beyond-january-iap-2023/.

I'm also realizing that if you're using RC to test this and not a locally running instance of `mit-learn`, you'll need to disable CORS. You can Google various ways to do this for testing, and that's one option. The other is to spin up `mit-learn` on your own and set `CORS_ALLOWED_ORIGINS`, `ALLOWED_REDIRECT_HOSTS` and `CSRF_TRUSTED_ORIGINS`, making sure your OCW domains are included in all of these.
author_association: CONTRIBUTOR