Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embeddable mode #213 #10

Merged
merged 2 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions lib/plausible/site/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Plausible.Site do
field :timezone, :string
field :public, :boolean
field :embeddable, :boolean
field :external_css, :string

many_to_many :members, User, join_through: Plausible.Site.Membership
has_one :google_auth, GoogleAuth
Expand Down Expand Up @@ -47,6 +48,20 @@ defmodule Plausible.Site do
change(site, embeddable: false)
end

def add_external_css(site, external_css) do
site
|> cast(%{external_css: external_css}, [:external_css])
|> validate_required(:external_css)
|> validate_format(:external_css, ~r/^https:\/\/.*$/,
message: "The style sheet must be served as https."
)
|> validate_url(:external_css)
end

def delete_external_css(site) do
change(site, external_css: nil)
end

defp clean_domain(changeset) do
clean_domain =
(get_field(changeset, :domain) || "")
Expand All @@ -61,4 +76,27 @@ defmodule Plausible.Site do
domain: clean_domain
})
end

# https://gist.github.com/atomkirk/74b39b5b09c7d0f21763dd55b877f998
defp validate_url(changeset, field, opts \\ []) do
validate_change(changeset, field, fn _, value ->
case URI.parse(value) do
%URI{scheme: nil} ->
"is missing a scheme (e.g. https)"

%URI{host: nil} ->
"is missing a host"

%URI{host: host} ->
case :inet.gethostbyname(Kernel.to_charlist(host)) do
{:ok, _} -> nil
{:error, _} -> "invalid host"
end
end
|> case do
error when is_binary(error) -> [{field, Keyword.get(opts, :message, error)}]
_ -> []
end
end)
end
end
35 changes: 35 additions & 0 deletions lib/plausible_web/controllers/site_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,13 @@ defmodule PlausibleWeb.SiteController do
def settings_visibility(conn, %{"website" => website}) do
site = Sites.get_for_user!(conn.assigns[:current_user].id, website)
shared_links = Repo.all(from l in Plausible.Site.SharedLink, where: l.site_id == ^site.id)
changeset = Plausible.Site.changeset(site)

conn
|> assign(:skip_plausible_tracking, true)
|> render("settings_visibility.html",
site: site,
changeset: changeset,
shared_links: shared_links,
layout: {PlausibleWeb.LayoutView, "site_settings.html"}
)
Expand Down Expand Up @@ -656,4 +658,37 @@ defmodule PlausibleWeb.SiteController do
end)
|> Repo.transaction()
end

def add_external_css(conn, %{"website" => website, "site" => site_changes}) do
site = Sites.get_for_user!(conn.assigns[:current_user].id, website)
changeset = Plausible.Site.add_external_css(site, site_changes["external_css"])

case Repo.update(changeset) do
{:ok, _site} ->
redirect(conn, to: "/#{URI.encode_www_form(site.domain)}/settings/visibility")

{:error, changeset} ->
shared_links = Repo.all(from l in Plausible.Site.SharedLink, where: l.site_id == ^site.id)

conn
|> assign(:skip_plausible_tracking, true)
|> render("settings_visibility.html",
site: site,
changeset: changeset,
shared_links: shared_links,
layout: {PlausibleWeb.LayoutView, "site_settings.html"}
)
end
end

def delete_external_css(conn, %{"website" => website}) do
site =
Sites.get_for_user!(conn.assigns[:current_user].id, website)
|> Plausible.Site.delete_external_css()
|> Repo.update!()

conn
|> put_flash(:success, "External CSS for #{site.domain} deleted successfully.")
|> redirect(to: "/#{URI.encode_www_form(site.domain)}/settings/visibility")
end
end
16 changes: 13 additions & 3 deletions lib/plausible_web/controllers/stats_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,22 @@ defmodule PlausibleWeb.StatsController do
Repo.get_by(Plausible.Site.SharedLink, slug: slug)
|> Repo.preload(:site)

embed_mode = Enum.at(conn.path_info, 1) == "embed"
if shared_link do
embed_mode = Enum.at(conn.path_info, 1) == "embed"
embed_link = if(embed_mode, do: "/embed", else: "")

embed_link = if(embed_mode, do: "/embed", else: "")
theme_index = Enum.find_index(conn.path_info, fn x -> x == "theme" end)

admin_selected_theme =
if(
theme_index,
do: Enum.at(conn.path_info, theme_index + 1),
else: nil
)

if shared_link do
if shared_link.password_hash do
conn
|> put_session("admin_selected_theme", admin_selected_theme)
|> put_session("embed_mode", embed_mode)
|> assign(:skip_plausible_tracking, true)
|> render("shared_link_password.html",
Expand All @@ -100,6 +109,7 @@ defmodule PlausibleWeb.StatsController do
)
else
conn
|> put_session("admin_selected_theme", admin_selected_theme)
|> put_session("embed_mode", embed_mode)
|> shared_link_auth_success(shared_link)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule PlausibleWeb.SharedLinkThemeSelectionPlug do
if(
theme_index,
do: Enum.at(conn.path_info, theme_index + 1),
else: get_session(conn, "selected_theme")
else: nil
)

conn
Expand Down
5 changes: 5 additions & 0 deletions lib/plausible_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ defmodule PlausibleWeb.Router do
post "/sites/:website/shared-links", SiteController, :create_shared_link
delete "/sites/:website/shared-links/:slug", SiteController, :delete_shared_link

put "/sites/:website/external-css", SiteController, :add_external_css
delete "/sites/:website/external-css", SiteController, :delete_external_css

get "/sites/:website/custom-domains/new", SiteController, :new_custom_domain
get "/sites/:website/custom-domains/dns-setup", SiteController, :custom_domain_dns_setup
get "/sites/:website/custom-domains/snippet", SiteController, :custom_domain_snippet
Expand Down Expand Up @@ -179,7 +182,9 @@ defmodule PlausibleWeb.Router do
delete "/:website", SiteController, :delete_site
delete "/:website/stats", SiteController, :reset_stats

get "/share/embed/:slug/theme/:theme_slug", StatsController, :shared_link
get "/share/embed/:slug", StatsController, :shared_link
get "/share/:slug/theme/:theme_slug", StatsController, :shared_link
get "/share/:slug", StatsController, :shared_link
post "/share/embed/:slug/authenticate", StatsController, :authenticate_shared_link
post "/share/:slug/authenticate", StatsController, :authenticate_shared_link
Expand Down
2 changes: 1 addition & 1 deletion lib/plausible_web/templates/layout/app.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<title><%= assigns[:title] || "Plausible · Simple, privacy-friendly alternative to Google Analytics" %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= render("_tracking.html", assigns) %>
<script type="text/javascript" data-pref="<%= Plug.Conn.get_session(@conn, "selected_theme") || (@conn.assigns[:current_user] && @conn.assigns[:current_user].theme) %>" src="<%= Routes.static_path(@conn, "/js/applyTheme.js") %>"></script>
<script type="text/javascript" data-pref="<%= ((Plug.Conn.get_session(@conn, "admin_selected_theme") != "user") && Plug.Conn.get_session(@conn, "admin_selected_theme")) || ((Plug.Conn.get_session(@conn, "admin_selected_theme") == "user") && Plug.Conn.get_session(@conn, "selected_theme")) || (@conn.assigns[:current_user] && @conn.assigns[:current_user].theme) %>" src="<%= Routes.static_path(@conn, "/js/applyTheme.js") %>"></script>
</head>
<body class="flex flex-col h-full bg-gray-50 dark:bg-gray-850">
<%= if !(@conn.assigns[:embed_mode] && @conn.assigns.site.embeddable) do %>
Expand Down
30 changes: 30 additions & 0 deletions lib/plausible_web/templates/site/settings_visibility.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,33 @@
</div>
</div>

<div class="shadow bg-white dark:bg-gray-800 sm:rounded-md sm:overflow-hidden py-6 px-4 sm:p-6">
<header class="relative">
<h2 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">External styles</h2>
<p class="mt-1 text-sm leading-5 text-gray-500 dark:text-gray-200">You can use external css style sheet but should be hosted securely (https).</p>
<%= link(to: "https://docs.plausible.io/external-css", target: "_blank") do %>
<svg class="w-6 h-6 absolute top-0 right-0 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg>
<% end %>
</header>
<%= if [email protected]_css do %>
<div class="mt-6">
<%= form_for @changeset, "/sites/#{URI.encode_www_form(@site.domain)}/external-css", [class: "max-w-xl"], fn f -> %>
<div class="col-span-4 sm:col-span-2">
<%= label f, :external_css, "External CSS URL", class: "block text-sm font-medium leading-5 text-gray-700 dark:text-gray-300" %>
<div class="mt-1">
<%= text_input f, :external_css, class: "shadow-sm dark:bg-gray-900 dark:text-gray-300 focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 dark:border-gray-500 rounded-md dark:bg-gray-800" %>
<%= error_tag f, :external_css %>
</div>
</div>
<%= submit "Save", class: "button mt-4" %>
<% end %>
</div>
<% else %>
<div class="mt-6 flex relative w-full max-w-xl text-sm">
<input type="text" readonly="readonly" value="<%= @site.external_css %>" class="transition bg-gray-100 dark:bg-gray-900 outline-none appearance-none border border-transparent rounded rounded-r-none w-full p-2 text-gray-700 dark:text-gray-300 focus:outline-none focus:border-gray-300 dark:focus:border-gray-500" />
<%= button(to: "/sites/#{URI.encode_www_form(@site.domain)}/external-css", method: :delete, class: "py-2 px-4 bg-gray-200 dark:bg-gray-850 text-red-600 dark:text-red-500 rounded-l-none hover:bg-gray-300 dark:hover:bg-gray-825", data: [confirm: "Are you sure you want to delete this external style sheet?"]) do %>
<svg class="feather feather-sm" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
<% end %>
</div>
<% end %>
</div>
36 changes: 29 additions & 7 deletions lib/plausible_web/templates/stats/stats.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,41 @@
<%= link("Click here to enable weekly email reports →", to: "/#{URI.encode_www_form(@site.domain)}/settings#email-reports", class: "py-2 block") %>
</div>
<% end %>
<%= if @valid_shared_link do %>
<div>
<%= if @selected_theme == "dark" do %>
<%= if @valid_shared_link && (Plug.Conn.get_session(@conn, "admin_selected_theme") == "user") do %>
<div class="flex">
<%= if !@selected_theme do %>
<div class="flex items-center space-x-3 mt-4">
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">System OFF</span>
<button onclick="location.href='<%="/#{URI.encode_www_form(@site.domain) <> theme_path(@conn, "light")}"%>'" class="bg-indigo-600 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring">
<span class="translate-x-5 inline-block h-5 w-5 rounded-full bg-white dark:bg-gray-800 shadow transform transition ease-in-out duration-200"></span>
</button>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Light/Dark Mode</span>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">ON</span>
</div>
<% else %>
<div class="flex items-center space-x-3 mt-4">
<button onclick="location.href='<%="/#{URI.encode_www_form(@site.domain) <> theme_path(@conn, "dark")}"%>'" class="bg-gray-200 dark:bg-gray-700 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring">
<div class="flex items-center space-x-3 mt-4 mr-12">
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">System OFF</span>
<button onclick="location.href='<%="/#{URI.encode_www_form(@site.domain)}"%>'" class="bg-gray-200 dark:bg-gray-700 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring">
<span class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white dark:bg-gray-800 shadow transform transition ease-in-out duration-200"></span>
</button>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Light/Dark Mode</span>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">ON</span>
</div>
<%= if @selected_theme == "light" do %>
<div class="flex items-center space-x-3 mt-4">
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Dark</span>
<button onclick="location.href='<%="/#{URI.encode_www_form(@site.domain) <> theme_path(@conn, "dark")}"%>'" class="bg-indigo-600 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring">
<span class="translate-x-5 inline-block h-5 w-5 rounded-full bg-white dark:bg-gray-800 shadow transform transition ease-in-out duration-200"></span>
</button>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Light</span>
</div>
<% else %>
<div class="flex items-center space-x-3 mt-4">
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Dark</span>
<button onclick="location.href='<%="/#{URI.encode_www_form(@site.domain) <> theme_path(@conn, "light")}"%>'" class="bg-gray-200 dark:bg-gray-700 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring">
<span class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white dark:bg-gray-800 shadow transform transition ease-in-out duration-200"></span>
</button>
<span class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">Light</span>
</div>
<% end %>
<% end %>
</div>
<% end %>
Expand Down Expand Up @@ -50,4 +69,7 @@
</div>
<% end %>
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/dashboard.js") %>"></script>
<%= if (@site.external_css) && !(@conn.assigns[:current_user]) do %>
<link href="<%= @site.external_css %>" rel="stylesheet">
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Plausible.Repo.Migrations.AddExternalCssToSites do
use Ecto.Migration

def change do
alter table(:sites) do
add :external_css, :string, null: true
end
end
end