portico: Add setting to put Google Analytics on selected portico pages.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-05-07 21:37:58 -07:00 committed by Tim Abbott
parent 8fb1f2af58
commit 4362cceffb
14 changed files with 106 additions and 34 deletions

View File

@ -31,6 +31,7 @@
"file-loader": "^6.0.0",
"flatpickr": "^4.5.7",
"font-awesome": "^4.7.0",
"ga-gtag": "^1.0.1",
"handlebars": "^4.7.2",
"handlebars-loader": "^1.7.1",
"html-webpack-plugin": "^4.0.0-beta.8",

View File

@ -1,4 +1,5 @@
import "./common.js";
import "../i18n.js";
import "../portico/header.js";
import "../portico/google-analytics.js";
import "../../styles/portico/portico-styles.scss";

View File

@ -0,0 +1,10 @@
import { gtag, install } from "ga-gtag";
export let config;
if (page_params.google_analytics_id !== undefined) {
install(page_params.google_analytics_id);
config = (info) => gtag("config", page_params.google_analytics_id, info);
} else {
config = () => {};
}

View File

@ -1,3 +1,4 @@
import * as google_analytics from './google-analytics.js';
import SimpleBar from 'simplebar';
import {activate_correct_tab} from './tabbed-instructions.js';
@ -93,6 +94,7 @@ const update_page = function (html_map, path) {
scrollToHash(markdownSB);
});
}
google_analytics.config({page_path: path});
};
new SimpleBar($(".sidebar")[0]);

View File

@ -1,3 +1,4 @@
import * as google_analytics from './google-analytics.js';
import blueslip from './../blueslip';
import { path_parts } from './landing-page';
@ -72,6 +73,7 @@ function update_path() {
}
window.history.pushState(state, '', next_path);
google_analytics.config({page_path: next_path});
}
function update_categories() {
@ -306,6 +308,7 @@ function dispatch(action, payload) {
case 'LOAD_PATH':
render(get_state_from_path());
google_analytics.config({page_path: window.location.pathname});
break;
default:

View File

@ -1,3 +1,4 @@
import * as google_analytics from './google-analytics.js';
import { detect_user_os } from './tabbed-instructions.js';
import render_tabs from './team.js';
@ -126,6 +127,7 @@ const apps_events = function () {
version = get_version_from_path();
update_page();
$("body").animate({ scrollTop: 0 }, 200);
google_analytics.config({page_path: window.location.pathname});
});
$(".apps a .icon").click(function (e) {
@ -137,6 +139,7 @@ const apps_events = function () {
update_path();
update_page();
$("body").animate({ scrollTop: 0 }, 200);
google_analytics.config({page_path: window.location.pathname});
return false;
});

View File

@ -44,4 +44,4 @@ API_FEATURE_LEVEL = 4
# historical commits sharing the same major version, in which case a
# minor version bump suffices.
PROVISION_VERSION = '82.1'
PROVISION_VERSION = '82.2'

View File

@ -5006,6 +5006,11 @@ functional-red-black-tree@^1.0.0, functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
ga-gtag@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ga-gtag/-/ga-gtag-1.0.1.tgz#c23d9b0619cee1eec7670f6db26dd071d614a6f4"
integrity sha512-wWPLuVwmfMfiK5KI7w59fN5kTONRnsSmnejoDo7+6tOulxxKgTSkB4kJcgBa3VfKAunvjopAOGp/5L/BTYZftw==
gamma@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/gamma/-/gamma-0.1.0.tgz#3315643403bf27906ca80ab37c36ece9440ef330"

View File

@ -16,6 +16,7 @@ from django.shortcuts import resolve_url
from django.utils.decorators import available_attrs
from django.utils.timezone import now as timezone_now
from django.conf import settings
from django.template.response import SimpleTemplateResponse
from zerver.lib.exceptions import UnexpectedWebhookEventType
from zerver.lib.queue import queue_json_publish
@ -825,3 +826,20 @@ def zulip_otp_required(view: Any=None,
redirect_field_name=redirect_field_name)
return decorator if (view is None) else decorator(view)
def add_google_analytics_context(context: Dict[str, Any]) -> None:
if settings.GOOGLE_ANALYTICS_ID is not None: # nocoverage
context.setdefault("page_params", {})["google_analytics_id"] = settings.GOOGLE_ANALYTICS_ID
def add_google_analytics(view_func: ViewFuncT) -> ViewFuncT:
@wraps(view_func)
def _wrapped_view_func(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
response = view_func(request, *args, **kwargs)
if isinstance(response, SimpleTemplateResponse):
if response.context_data is None:
response.context_data = {}
add_google_analytics_context(response.context_data)
elif response.status_code == 200: # nocoverage
raise TypeError("add_google_analytics requires a TemplateResponse")
return response
return _wrapped_view_func # type: ignore[return-value] # https://github.com/python/mypy/issues/1927

View File

@ -9,6 +9,7 @@ import os
import random
import re
from zerver.decorator import add_google_analytics_context
from zerver.lib.integrations import CATEGORIES, INTEGRATIONS, HubotIntegration, \
WebhookIntegration
from zerver.lib.request import has_request_variables, REQ
@ -123,6 +124,7 @@ class MarkdownDirectoryView(ApiURLView):
add_api_uri_context(api_uri_context, self.request)
api_uri_context["run_content_validators"] = True
context["api_uri_context"] = api_uri_context
add_google_analytics_context(context)
return context
def get(self, request: HttpRequest, article: str="") -> HttpResponse:
@ -170,6 +172,7 @@ class IntegrationView(ApiURLView):
context: Dict[str, Any] = super().get_context_data(**kwargs)
add_integrations_context(context)
add_integrations_open_graph_context(context, self.request)
add_google_analytics_context(context)
return context

View File

@ -7,7 +7,6 @@ from django.shortcuts import redirect, render
from django.utils import translation
from django.utils.cache import patch_cache_control
from zerver.context_processors import latest_info_context
from zerver.decorator import zulip_login_required
from zerver.forms import ToSForm
from zerver.models import Message, Stream, UserProfile, \
@ -25,6 +24,7 @@ from zerver.lib.utils import statsd, generate_random_token
from zerver.views.compatibility import is_outdated_desktop_app, \
is_unsupported_browser
from zerver.views.messages import get_latest_update_message_flag_activity
from zerver.views.portico import hello_view
from two_factor.utils import default_device
import calendar
@ -145,7 +145,7 @@ def home(request: HttpRequest) -> HttpResponse:
if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN:
return home_real(request)
return render(request, 'zerver/hello.html', latest_info_context())
return hello_view(request)
@zulip_login_required
def home_real(request: HttpRequest) -> HttpResponse:

View File

@ -1,23 +1,28 @@
from django.conf import settings
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.template.response import TemplateResponse
import ujson
from zerver.context_processors import get_realm_from_request
from zerver.decorator import redirect_to_login
from zerver.context_processors import get_realm_from_request, latest_info_context
from zerver.decorator import add_google_analytics, redirect_to_login
from zerver.models import Realm
from version import LATEST_DESKTOP_VERSION
@add_google_analytics
def apps_view(request: HttpRequest, _: str) -> HttpResponse:
if settings.ZILENCER_ENABLED:
return render(request, 'zerver/apps.html',
context={
"page_params": {
'electron_app_version': LATEST_DESKTOP_VERSION,
}
})
return TemplateResponse(
request,
'zerver/apps.html',
context={
"page_params": {
'electron_app_version': LATEST_DESKTOP_VERSION,
}
}
)
return HttpResponseRedirect('https://zulipchat.com/apps/', status=301)
@add_google_analytics
def plans_view(request: HttpRequest) -> HttpResponse:
realm = get_realm_from_request(request)
realm_plan_type = 0
@ -28,9 +33,13 @@ def plans_view(request: HttpRequest) -> HttpResponse:
return HttpResponseRedirect('https://zulipchat.com/plans')
if not request.user.is_authenticated:
return redirect_to_login(next="plans")
return render(request, "zerver/plans.html",
context={"realm_plan_type": realm_plan_type, 'free_trial_months': free_trial_months})
return TemplateResponse(
request,
"zerver/plans.html",
context={"realm_plan_type": realm_plan_type, 'free_trial_months': free_trial_months},
)
@add_google_analytics
def team_view(request: HttpRequest) -> HttpResponse:
if not settings.ZILENCER_ENABLED:
return HttpResponseRedirect('https://zulipchat.com/team/', status=301)
@ -41,7 +50,7 @@ def team_view(request: HttpRequest) -> HttpResponse:
except FileNotFoundError:
data = {'contrib': {}, 'date': "Never ran."}
return render(
return TemplateResponse(
request,
'zerver/team.html',
context={
@ -56,10 +65,24 @@ def get_isolated_page(request: HttpRequest) -> bool:
'''Accept a GET param `?nav=no` to render an isolated, navless page.'''
return request.GET.get('nav') == 'no'
def terms_view(request: HttpRequest) -> HttpResponse:
return render(request, 'zerver/terms.html',
context={'isolated_page': get_isolated_page(request)})
@add_google_analytics
def landing_view(request: HttpRequest, template_name: str) -> HttpResponse:
return TemplateResponse(request, template_name)
@add_google_analytics
def hello_view(request: HttpRequest) -> HttpResponse:
return TemplateResponse(request, 'zerver/hello.html', latest_info_context())
@add_google_analytics
def terms_view(request: HttpRequest) -> HttpResponse:
return TemplateResponse(
request, 'zerver/terms.html',
context={'isolated_page': get_isolated_page(request)},
)
@add_google_analytics
def privacy_view(request: HttpRequest) -> HttpResponse:
return render(request, 'zerver/privacy.html',
context={'isolated_page': get_isolated_page(request)})
return TemplateResponse(
request, 'zerver/privacy.html',
context={'isolated_page': get_isolated_page(request)},
)

View File

@ -370,3 +370,6 @@ FREE_TRIAL_MONTHS = None
# users, and you would like to save some disk space. Soft-deactivated
# returning users would still be caught-up normally.
AUTO_CATCH_UP_SOFT_DEACTIVATED_USERS = True
# Enables Google Analytics on selected portico pages.
GOOGLE_ANALYTICS_ID: Optional[str] = None

View File

@ -35,7 +35,6 @@ import zerver.views.streams
import zerver.views.realm
import zerver.views.digest
import zerver.views.messages
from zerver.context_processors import latest_info_context
import zerver.views.realm_export
import zerver.views.upload
@ -548,23 +547,24 @@ i18n_urls = [
url(r'^integrations/(.*)$', IntegrationView.as_view()),
# Landing page, features pages, signup form, etc.
url(r'^hello/$', TemplateView.as_view(template_name='zerver/hello.html',
get_context_data=latest_info_context),
name='landing-page'),
url(r'^hello/$', zerver.views.portico.hello_view, name='landing-page'),
url(r'^new-user/$', RedirectView.as_view(url='/hello', permanent=True)),
url(r'^features/$', TemplateView.as_view(template_name='zerver/features.html')),
url(r'^features/$', zerver.views.portico.landing_view, {'template_name': 'zerver/features.html'}),
url(r'^plans/$', zerver.views.portico.plans_view, name='plans'),
url(r'^apps/(.*)$', zerver.views.portico.apps_view, name='zerver.views.home.apps_view'),
url(r'^team/$', zerver.views.portico.team_view),
url(r'^history/$', TemplateView.as_view(template_name='zerver/history.html')),
url(r'^why-zulip/$', TemplateView.as_view(template_name='zerver/why-zulip.html')),
url(r'^for/open-source/$', TemplateView.as_view(template_name='zerver/for-open-source.html')),
url(r'^for/companies/$', TemplateView.as_view(template_name='zerver/for-companies.html')),
url(r'^for/working-groups-and-communities/$',
TemplateView.as_view(template_name='zerver/for-working-groups-and-communities.html')),
url(r'^for/mystery-hunt/$', TemplateView.as_view(template_name='zerver/for-mystery-hunt.html')),
url(r'^security/$', TemplateView.as_view(template_name='zerver/security.html')),
url(r'^atlassian/$', TemplateView.as_view(template_name='zerver/atlassian.html')),
url(r'^history/$', zerver.views.portico.landing_view, {'template_name': 'zerver/history.html'}),
url(r'^why-zulip/$', zerver.views.portico.landing_view, {'template_name': 'zerver/why-zulip.html'}),
url(r'^for/open-source/$', zerver.views.portico.landing_view,
{'template_name': 'zerver/for-open-source.html'}),
url(r'^for/companies/$', zerver.views.portico.landing_view,
{'template_name': 'zerver/for-companies.html'}),
url(r'^for/working-groups-and-communities/$', zerver.views.portico.landing_view,
{'template_name': 'zerver/for-working-groups-and-communities.html'}),
url(r'^for/mystery-hunt/$', zerver.views.portico.landing_view,
{'template_name': 'zerver/for-mystery-hunt.html'}),
url(r'^security/$', zerver.views.portico.landing_view, {'template_name': 'zerver/security.html'}),
url(r'^atlassian/$', zerver.views.portico.landing_view, {'template_name': 'zerver/atlassian.html'}),
# Terms of Service and privacy pages.
url(r'^terms/$', zerver.views.portico.terms_view, name='terms'),