analytics/lib/workers/traffic_change_notifier.ex
hq1 e3af1a317d
Onboarding improvements (#4459)
* Migration: add installation meta

* Update site schema with installation meta

* Remove VERIFICATION_ENABLED env var

* Add context API to create/remove special goals

* Add context api to update installation meta

* Remove verification enabled check

* Update new progress flow definitions

* Update generic components

* Remove internal /status API

* Implement installation live view

* Update traffic change notifier link

* Update verification, no more modal

* Update routes

* Remove focus.html - will unify everything under app layout

* Fix broken link

* Update templates with focus_box mostly

* Update controller tests

* Update controllers and stop using the focus layout

* copy changes

* Update verification.ex

* Remove dead template

* Update settings_general.html.heex

* Update copy in tests

* Update installation.ex

* Remove dangling dot

* Fix link

* Update installation.ex

* Update installation.ex

* Better tooltips?

* Simpler labels

* Revert "Simpler labels"

This reverts commit 797560ef82f2067458b03b884be5aecc8fdc72bc.

* Add copy to clipboard link and fix snippet's dark mode

* Offer installation detection skip only if ws connected

* Put COPY link at the bottom with background

* Make tooltips link to docs

* Fix cherry-pick gone wrong

* Hide tooltips on mobile screens

* WIP: 404 tracking wizard

* Revert "WIP: 404 tracking wizard"

This reverts commit a9c9c79bbd.

* Update lib/plausible_web/live/components/verification.ex

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>

* Update lib/plausible_web/live/installation.ex

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>

* Use current_user from socket.assigns

* Update lib/plausible_web/live/installation.ex

Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>

* Use current_user from socket.assigns

* Use conn.private to steer verification tests

* Drop non-sticky tooltip in favour of component parametrization

Co-authored-by: Artur Pata <artur.pata@gmail.com>

* Reapply "WIP: 404 tracking wizard"

This reverts commit 3ba81671d7.

* Fix installation tests including 404 tracking

* Fixup the tooltip component

* Format

* Update installation.ex

* Put flash whenever installation option changes

* Use last known installation type on domain change

* Extract user flow definition to provide compile-time checks

* See if this helps running CE migrations successfully

* Use `styled_link` on registration/login views

* Don't crash when there's no conn.private carried over

* Format

* Push "Determining installation type" message a bit lower

* Use links and footer lists uniformly

This commit introduces a `<.focus_list/>` component
for rendering focus box footer links with colored
discs. It also equips generic link components
with the ability of sending non-GET requests
along with CSRF token, so we can apply uniform
styling and stop using legacy Phoenix link tags.

cc @zoldar @apata

* ws 👾

* Render more descriptive flashes on script config change

---------

Co-authored-by: Marko Saric <34340819+metmarkosaric@users.noreply.github.com>
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Co-authored-by: Artur Pata <artur.pata@gmail.com>
2024-09-02 12:49:54 +02:00

126 lines
3.5 KiB
Elixir

defmodule Plausible.Workers.TrafficChangeNotifier do
@moduledoc """
Oban service sending out traffic drop/spike notifications
"""
use Plausible.Repo
alias Plausible.Stats.Query
alias Plausible.Site.TrafficChangeNotification
alias PlausibleWeb.Router.Helpers, as: Routes
use Oban.Worker, queue: :spike_notifications
@at_most_every "12 hours"
@impl Oban.Worker
def perform(_job, clickhouse \\ Plausible.Stats.Clickhouse) do
today = Date.utc_today()
notifications =
Repo.all(
from sn in TrafficChangeNotification,
where: is_nil(sn.last_sent),
or_where: sn.last_sent < fragment("now() - INTERVAL ?", @at_most_every),
join: s in Plausible.Site,
on: sn.site_id == s.id,
where: not s.locked,
join: sm in Plausible.Site.Membership,
on: sm.site_id == s.id,
where: sm.role == :owner,
join: u in Plausible.Auth.User,
on: u.id == sm.user_id,
where: is_nil(u.accept_traffic_until) or u.accept_traffic_until > ^today,
preload: [site: s]
)
for notification <- notifications do
case notification.type do
:spike ->
current_visitors = clickhouse.current_visitors(notification.site)
if current_visitors >= notification.threshold do
query = Query.from(notification.site, %{"period" => "realtime"})
sources = clickhouse.top_sources_for_spike(notification.site, query, 3, 1)
notify_spike(notification, current_visitors, sources)
end
:drop ->
current_visitors = clickhouse.current_visitors_12h(notification.site)
if current_visitors < notification.threshold do
notify_drop(notification, current_visitors)
end
end
end
:ok
end
defp notify_spike(notification, current_visitors, sources) do
for recipient <- notification.recipients do
send_spike_notification(recipient, notification.site, current_visitors, sources)
end
notification
|> TrafficChangeNotification.was_sent()
|> Repo.update()
end
defp notify_drop(notification, current_visitors) do
for recipient <- notification.recipients do
send_drop_notification(recipient, notification.site, current_visitors)
end
notification
|> TrafficChangeNotification.was_sent()
|> Repo.update()
end
defp send_spike_notification(recipient, site, current_visitors, sources) do
site = Repo.preload(site, :members)
dashboard_link =
if Enum.any?(site.members, &(&1.email == recipient)) do
Routes.stats_url(PlausibleWeb.Endpoint, :stats, site.domain, [])
end
template =
PlausibleWeb.Email.spike_notification(
recipient,
site,
current_visitors,
sources,
dashboard_link
)
Plausible.Mailer.send(template)
end
defp send_drop_notification(recipient, site, current_visitors) do
site = Repo.preload(site, :members)
{dashboard_link, installation_link} =
if Enum.any?(site.members, &(&1.email == recipient)) do
{
Routes.stats_url(PlausibleWeb.Endpoint, :stats, site.domain, []),
Routes.site_url(PlausibleWeb.Endpoint, :installation, site.domain,
flow: PlausibleWeb.Flows.review()
)
}
else
{nil, nil}
end
template =
PlausibleWeb.Email.drop_notification(
recipient,
site,
current_visitors,
dashboard_link,
installation_link
)
Plausible.Mailer.send(template)
end
end