From 1ef23dd3132a2ee91a1c1c492f76c2591688ab92 Mon Sep 17 00:00:00 2001
From: Dominik George <dominik.george@teckids.org>
Date: Sat, 14 Jan 2023 22:48:26 +0100
Subject: [PATCH] Reimplement passing of settings to frontend

The frontend now gets a dictionary passed explicitly. It is made
available in `$root.$aleksisFrontendSettings`.
---
 aleksis/core/assets/app/apollo.js          | 15 ++++++++++++++-
 aleksis/core/assets/plugins/aleksis.js     | 17 +++++++++--------
 aleksis/core/templates/core/vue_index.html |  6 ++++--
 aleksis/core/util/core_helpers.py          | 16 +++++++++++++++-
 4 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/aleksis/core/assets/app/apollo.js b/aleksis/core/assets/app/apollo.js
index 84c47c6bb..35b1b231d 100644
--- a/aleksis/core/assets/app/apollo.js
+++ b/aleksis/core/assets/app/apollo.js
@@ -80,6 +80,19 @@ function addErrorSnackbarItem(messageKey) {
   });
 }
 
+/**
+ * Construct the GraphQL endpoint URI.
+ *
+ * @returns The URI of the GraphQL endpoint on the AlekSIS server
+ */
+function getGraphqlURL() {
+  const settings = JSON.parse(
+    document.getElementById("frontend_settings").textContent
+  );
+  const base = settings.urls.base || window.location.origin;
+  return new URL(settings.urls.graphql, base);
+}
+
 // Define Apollo links for handling query operations.
 const links = [
   // Automatically retry failed queries
@@ -95,7 +108,7 @@ const links = [
   }),
   // Finally, the HTTP link to the real backend (Django)
   new HttpLink({
-    uri: window.location.origin + "/graphql/",
+    uri: getGraphqlURL(),
   }),
 ];
 
diff --git a/aleksis/core/assets/plugins/aleksis.js b/aleksis/core/assets/plugins/aleksis.js
index 84b7b15f5..2c91eebf9 100644
--- a/aleksis/core/assets/plugins/aleksis.js
+++ b/aleksis/core/assets/plugins/aleksis.js
@@ -9,13 +9,17 @@ console.debug("Defining AleksisVue plugin");
 const AleksisVue = {};
 
 AleksisVue.install = function (Vue, options) {
-  /**
+  /*
    * The browser title when the app was loaded.
    *
    * Thus, it is injected from Django in the vue_index template.
    */
   Vue.$pageBaseTitle = document.title;
 
+  Vue.$aleksisFrontendSettings = JSON.parse(
+    document.getElementById("frontend_settings").textContent
+  );
+
   /**
    * Configure Sentry if desired.
    *
@@ -23,18 +27,15 @@ AleksisVue.install = function (Vue, options) {
    * in the vue_index template.
    */
   Vue.$configureSentry = function () {
-    if (document.getElementById("sentry_settings") !== null) {
+    if (Vue.$aleksisFrontendSettings.sentry.enabled) {
       const Sentry = import("@sentry/vue");
       const { BrowserTracing } = import("@sentry/tracing");
 
-      const sentry_settings = JSON.parse(
-        document.getElementById("sentry_settings").textContent
-      );
       Sentry.init({
         Vue,
-        dsn: sentry_settings.dsn,
-        environment: sentry_settings.environment,
-        tracesSampleRate: sentry_settings.traces_sample_rate,
+        dsn: Vue.$aleksisFrontendSettings.sentry.dsn,
+        environment: Vue.$aleksisFrontendSettings.sentry.environment,
+        tracesSampleRate: Vue.$aleksisFrontendSettings.sentry.traces_sample_rate,
         logError: true,
         integrations: [
           new BrowserTracing({
diff --git a/aleksis/core/templates/core/vue_index.html b/aleksis/core/templates/core/vue_index.html
index f362963d9..e541feb6e 100644
--- a/aleksis/core/templates/core/vue_index.html
+++ b/aleksis/core/templates/core/vue_index.html
@@ -5,6 +5,8 @@
 
 <html>
   <head>
+    <base href="{{ BASE_URL }}">
+
     {% include "core/partials/meta.html" %}
     <title>{{ request.site.preferences.general__title }}</title>
 
@@ -12,10 +14,10 @@
       {% if SENTRY_TRACE_ID %}
         <meta name="sentry-trace" content="{{ SENTRY_TRACE_ID }}"/>
       {% endif %}
-      {% include_js "Sentry" %}
-      {{ SENTRY_SETTINGS|json_script:"sentry_settings" }}
     {% endif %}
 
+    {{ FRONTEND_SETTINGS|json_script:"frontend_settings" }}
+
     {% vite_hmr_client %}
   </head>
 
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index f8ff683de..d43f7fc78 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -13,6 +13,7 @@ from django.core.files import File
 from django.db.models import Model, QuerySet
 from django.http import HttpRequest
 from django.shortcuts import get_object_or_404
+from django.urls import reverse
 from django.utils import timezone
 from django.utils.crypto import get_random_string
 from django.utils.functional import lazy
@@ -224,16 +225,29 @@ def custom_information_processor(request: Union[HttpRequest, None]) -> dict:
         regrouped_pwa_icons.setdefault(pwa_icon.rel, {})
         regrouped_pwa_icons[pwa_icon.rel][pwa_icon.size] = pwa_icon
 
+    # This dictionary is passed to the frontend and made available as
+    #  `$root.$aleksisFrontendSettings` in Vue.
+    frontend_settings = {
+        "sentry": {
+            "enabled": settings.SENTRY_ENABLED,
+        },
+        "urls": {
+            "base": settings.BASE_URL,
+            "graphql": reverse("graphql"),
+        }
+    }
+
     context = {
         "ADMINS": settings.ADMINS,
         "PWA_ICONS": regrouped_pwa_icons,
         "SENTRY_ENABLED": settings.SENTRY_ENABLED,
         "SITE_PREFERENCES": get_site_preferences(),
         "BASE_URL": settings.BASE_URL,
+        "FRONTEND_SETTINGS": frontend_settings,
     }
 
     if settings.SENTRY_ENABLED:
-        context["SENTRY_SETTINGS"] = settings.SENTRY_SETTINGS
+        frontend_settings["sentry"].update(settings.SENTRY_SETTINGS)
 
         import sentry_sdk
 
-- 
GitLab