summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2020-02-20 11:58:37 +0000
committerlain <lain@soykaf.club>2020-02-20 11:58:37 +0000
commite0b2de63853e9a14b72faddf6e1180a098728205 (patch)
treedaef5b359ffb611face916497c14342e75ac92a6
parentcf4ecffcea84d9b214f922a973d50c699317a202 (diff)
parent50d9fcbe29acae63ad2aec4eadedf7b9ba614428 (diff)
Merge branch 'feature/new-registrations-digest' into 'develop'
New users digest email Closes #1514 See merge request pleroma/pleroma!2128
-rw-r--r--CHANGELOG.md1
-rw-r--r--config/config.exs8
-rw-r--r--config/description.exs14
-rw-r--r--config/test.exs2
-rw-r--r--docs/configuration/cheatsheet.md4
-rw-r--r--lib/pleroma/emails/new_users_digest_email.ex32
-rw-r--r--lib/pleroma/web/templates/email/new_users_digest.html.eex158
-rw-r--r--lib/pleroma/web/templates/layout/email_styled.html.eex193
-rw-r--r--lib/pleroma/web/views/email_view.ex4
-rw-r--r--lib/pleroma/workers/cron/new_users_digest_worker.ex60
-rw-r--r--test/workers/cron/new_users_digest_worker_test.exs32
11 files changed, 506 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e838983b..ce0f584cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -72,6 +72,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- User notification settings: Add `privacy_option` option.
- Support for custom Elixir modules (such as MRF policies)
- User settings: Add _This account is a_ option.
+- A new users admin digest email
- OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`).
<details>
<summary>API Changes</summary>
diff --git a/config/config.exs b/config/config.exs
index ccc0c4e52..664572cf3 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -480,13 +480,15 @@ config :pleroma, Oban,
transmogrifier: 20,
scheduled_activities: 10,
background: 5,
- attachments_cleanup: 5
+ attachments_cleanup: 5,
+ new_users_digest: 1
],
crontab: [
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
{"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
{"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker},
- {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker}
+ {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
+ {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
]
config :pleroma, :workers,
@@ -560,6 +562,8 @@ config :pleroma, Pleroma.Emails.UserEmail,
text_muted_color: "#b9b9ba"
}
+config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false
+
config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics"
config :pleroma, Pleroma.ScheduledActivity,
diff --git a/config/description.exs b/config/description.exs
index 0c0f4af3c..53d980c83 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2504,6 +2504,20 @@ config :pleroma, :config_description, [
},
%{
group: :pleroma,
+ key: Pleroma.Emails.NewUsersDigestEmail,
+ type: :group,
+ description: "New users admin email digest",
+ children: [
+ %{
+ key: :enabled,
+ type: :boolean,
+ description: "enables new users admin digest email when `true`",
+ suggestions: [false]
+ }
+ ]
+ },
+ %{
+ group: :pleroma,
key: :oauth2,
type: :group,
description: "Configure OAuth 2 provider capabilities",
diff --git a/config/test.exs b/config/test.exs
index 078c46205..6bea09380 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -94,6 +94,8 @@ config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
config :pleroma, :modules, runtime_dir: "test/fixtures/modules"
+config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true
+
if File.exists?("./config/test.secret.exs") do
import_config "test.secret.exs"
else
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 2bd935983..c9559fe85 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -501,6 +501,10 @@ Email notifications settings.
- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo.
- `:styling` - a map with color settings for email templates.
+### Pleroma.Emails.NewUsersDigestEmail
+
+- `:enabled` - a boolean, enables new users admin digest email when `true`. Defaults to `false`.
+
## Background jobs
### Oban
diff --git a/lib/pleroma/emails/new_users_digest_email.ex b/lib/pleroma/emails/new_users_digest_email.ex
new file mode 100644
index 000000000..7d16b807f
--- /dev/null
+++ b/lib/pleroma/emails/new_users_digest_email.ex
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Emails.NewUsersDigestEmail do
+ use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email_styled}
+
+ defp instance_notify_email do
+ Pleroma.Config.get([:instance, :notify_email]) || Pleroma.Config.get([:instance, :email])
+ end
+
+ def new_users(to, users_and_statuses) do
+ instance_name = Pleroma.Config.get([:instance, :name])
+ styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling])
+
+ logo_url =
+ Pleroma.Web.Endpoint.url() <>
+ Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo])
+
+ new()
+ |> to({to.name, to.email})
+ |> from({instance_name, instance_notify_email()})
+ |> subject("#{instance_name} New Users")
+ |> render_body("new_users_digest.html", %{
+ title: "New Users",
+ users_and_statuses: users_and_statuses,
+ instance: instance_name,
+ styling: styling,
+ logo_url: logo_url
+ })
+ end
+end
diff --git a/lib/pleroma/web/templates/email/new_users_digest.html.eex b/lib/pleroma/web/templates/email/new_users_digest.html.eex
new file mode 100644
index 000000000..40d9b8381
--- /dev/null
+++ b/lib/pleroma/web/templates/email/new_users_digest.html.eex
@@ -0,0 +1,158 @@
+<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %>
+ <%# user card START %>
+ <div style="background-color:transparent;">
+ <div class="block-grid mixed-two-up no-stack"
+ style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
+ <div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
+ <!--[if (mso)|(IE)]><td align="center" width="147" style="background-color:<%= @styling.content_background_color%>;width:76px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 20px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num3"
+ style="display: table-cell; vertical-align: top; max-width: 320px; min-width: 76px; width: 76px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 20px;">
+ <!--<![endif]-->
+ <div align="left" class="img-container left "
+ style="padding-right: 0px;padding-left: 0px;">
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="left"><![endif]--><img
+ alt="<%= user.name %>" border="0" class="left " src="<%= avatar_url(user) %>"
+ style="text-decoration: none; -ms-interpolation-mode: bicubic; border: 0; height: auto; width: 100%; max-width: 76px; display: block;"
+ title="<%= user.name %>" width="76" />
+ <!--[if mso]></td></tr></table><![endif]-->
+ </div>
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td><td align="center" width="442" style="background-color:<%= @styling.content_background_color%>;width:442px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num9"
+ style="display: table-cell; vertical-align: top; min-width: 320px; max-width: 441px; width: 442px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+ <!--<![endif]-->
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
+ <div
+ style="color:<%= @styling.text_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
+ <div
+ style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_color %>;">
+ <p style="font-size: 14px; line-height: 19px; margin: 0;"><span
+ style="font-size: 16px; color: <%= @styling.text_color %>;"><%= user.name %></span></p>
+ <p style="font-size: 14px; line-height: 19px; margin: 0;"><span
+ style="font-size: 16px;"><%= link "@" <> user.nickname, style: "color: #{@styling.link_color};text-decoration: none;", to: admin_user_url(user) %></span></p>
+ <p style="font-size: 14px; line-height: 19px; margin: 0;"><span
+ style="font-size: 16px;">Total: <%= total_statuses %></span></p>
+ </div>
+ </div>
+ <!--[if mso]></td></tr></table><![endif]-->
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+ </div>
+ </div>
+ </div>
+ <%# user card END %>
+
+ <%= if latest_status do %>
+ <div style="background-color:transparent;">
+ <div class="block-grid"
+ style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
+ <div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
+ <!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 15px; padding-left: 15px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num12"
+ style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 15px; padding-left: 15px;">
+ <!--<![endif]-->
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
+ <div
+ style="color:<%= @styling.text_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
+ <div
+ style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_color %>;">
+ <span style="font-size: 16px; line-height: 19px;"><%= raw latest_status.object.data["content"] %></span></div>
+ </div>
+ <!--[if mso]></td></tr></table><![endif]-->
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 15px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
+ <div
+ style="color:<%= @styling.text_muted_color %>;font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:15px;">
+ <div
+ style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 12px; line-height: 14px; color: <%= @styling.text_muted_color %>;">
+ <p style="font-size: 14px; line-height: 16px; margin: 0;"><%= format_date latest_status.object.data["published"] %></p>
+ </div>
+ </div>
+ <!--[if mso]></td></tr></table><![endif]-->
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+ </div>
+ </div>
+ </div>
+ <% end %>
+ <%# divider start %>
+ <div style="background-color:transparent;">
+ <div class="block-grid"
+ style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
+ <div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
+ <!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num12"
+ style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+ <!--<![endif]-->
+ <table border="0" cellpadding="0" cellspacing="0" class="divider" role="presentation"
+ style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"
+ valign="top" width="100%">
+ <tbody>
+ <tr style="vertical-align: top;" valign="top">
+ <td class="divider_inner"
+ style="word-break: break-word; vertical-align: top; min-width: 100%; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 10px;"
+ valign="top">
+ <table align="center" border="0" cellpadding="0" cellspacing="0" class="divider_content"
+ height="0" role="presentation"
+ style="table-layout: fixed; vertical-align: top; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; border-top: 1px solid <%= @styling.text_color %>; height: 0px;"
+ valign="top" width="100%">
+ <tbody>
+ <tr style="vertical-align: top;" valign="top">
+ <td height="0"
+ style="word-break: break-word; vertical-align: top; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"
+ valign="top"><span></span></td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+ </div>
+ </div>
+ </div>
+
+ <%# divider end %>
+ <%# user card END %>
+<% end %>
diff --git a/lib/pleroma/web/templates/layout/email_styled.html.eex b/lib/pleroma/web/templates/layout/email_styled.html.eex
new file mode 100644
index 000000000..ca2caaf4d
--- /dev/null
+++ b/lib/pleroma/web/templates/layout/email_styled.html.eex
@@ -0,0 +1,193 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office"
+ xmlns:v="urn:schemas-microsoft-com:vml">
+
+<head>
+ <!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+ <meta content="width=device-width" name="viewport" />
+ <!--[if !mso]><!-->
+ <meta content="IE=edge" http-equiv="X-UA-Compatible" />
+ <!--<![endif]-->
+ <title><%= @email.subject %></title>
+ <!--[if !mso]><!-->
+ <!--<![endif]-->
+ <style type="text/css">
+ body {
+ margin: 0;
+ padding: 0;
+ }
+
+ a {
+
+ color: <%= @styling.link_color %>;
+ text-decoration: none;
+ }
+
+ table,
+ td,
+ tr {
+ vertical-align: top;
+ border-collapse: collapse;
+ }
+
+ * {
+ line-height: inherit;
+ }
+
+ a[x-apple-data-detectors=true] {
+ color: inherit !important;
+ text-decoration: none !important;
+ }
+ </style>
+ <style id="media-query" type="text/css">
+ @media (max-width: 610px) {
+
+ .block-grid,
+ .col {
+ min-width: 320px !important;
+ max-width: 100% !important;
+ display: block !important;
+ }
+
+ .block-grid {
+ width: 100% !important;
+ }
+
+ .col {
+ width: 100% !important;
+ }
+
+ .col>div {
+ margin: 0 auto;
+ }
+
+ .no-stack .col {
+ min-width: 0 !important;
+ display: table-cell !important;
+ }
+
+ .no-stack.two-up .col {
+ width: 50% !important;
+ }
+
+ .no-stack .col.num4 {
+ width: 33% !important;
+ }
+
+ .no-stack .col.num8 {
+ width: 66% !important;
+ }
+
+ .no-stack .col.num4 {
+ width: 33% !important;
+ }
+
+ .no-stack .col.num3 {
+ width: 25% !important;
+ }
+
+ .no-stack .col.num6 {
+ width: 50% !important;
+ }
+
+ .no-stack .col.num9 {
+ width: 75% !important;
+ }
+
+ }
+ </style>
+</head>
+
+<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: <%= @styling.background_color %>;">
+ <!--[if IE]><div class="ie-browser"><![endif]-->
+ <table bgcolor="<%= @styling.background_color %>" cellpadding="0" cellspacing="0" class="nl-container" role="presentation"
+ style="table-layout: fixed; vertical-align: top; min-width: 320px; Margin: 0 auto; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: <%= @styling.background_color %>; width: 100%;"
+ valign="top" width="100%">
+ <tbody>
+ <tr style="vertical-align: top;" valign="top">
+ <td style="word-break: break-word; vertical-align: top;" valign="top">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color:<%= @styling.background_color %>"><![endif]-->
+
+ <%# header %>
+ <div style="background-color:transparent;">
+ <div class="block-grid"
+ style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
+ <div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
+ <!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num12"
+ style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+ <!--<![endif]-->
+ <div align="center" class="img-container center"
+ style="padding-right: 0px;padding-left: 0px;">
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr style="line-height:0px"><td style="padding-right: 0px;padding-left: 0px;" align="center"><![endif]--><img
+ align="center" alt="Image" border="0" class="center" src="<%= @logo_url %>"
+ style="text-decoration: none; -ms-interpolation-mode: bicubic; border: 0; height: 80px; width: auto; max-height: 80px; display: block;"
+ title="Image" height="80" />
+ <!--[if mso]></td></tr></table><![endif]-->
+ </div>
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+ </div>
+ </div>
+ </div>
+
+
+ <%# title %>
+ <%= if @title do %>
+ <div style="background-color:transparent;">
+ <div class="block-grid"
+ style="Margin: 0 auto; min-width: 320px; max-width: 590px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; background-color: <%= @styling.content_background_color%>;">
+ <div style="border-collapse: collapse;display: table;width: 100%;background-color:<%= @styling.content_background_color%>;">
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:transparent;"><tr><td align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:590px"><tr class="layout-full-width" style="background-color:<%= @styling.content_background_color%>"><![endif]-->
+ <!--[if (mso)|(IE)]><td align="center" width="590" style="background-color:<%= @styling.content_background_color%>;width:590px; border-top: 0px solid transparent; border-left: 0px solid transparent; border-bottom: 0px solid transparent; border-right: 0px solid transparent;" valign="top"><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 0px; padding-left: 0px; padding-top:5px; padding-bottom:5px;"><![endif]-->
+ <div class="col num12"
+ style="min-width: 320px; max-width: 590px; display: table-cell; vertical-align: top; width: 590px;">
+ <div style="width:100% !important;">
+ <!--[if (!mso)&(!IE)]><!-->
+ <div
+ style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:5px; padding-bottom:5px; padding-right: 0px; padding-left: 0px;">
+ <!--<![endif]-->
+ <!--[if mso]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; font-family: Arial, sans-serif"><![endif]-->
+ <div
+ style="line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
+ <div
+ style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;line-height: 14px; color: <%= @styling.header_color %>;">
+ <p style="line-height: 36px; text-align: center; margin: 0;"><span
+ style="font-size: 30px; color: <%= @styling.header_color %>;"><%= @title %></span></p>
+ </div>
+ </div>
+ <!--[if mso]></td></tr></table><![endif]-->
+ <!--[if (!mso)&(!IE)]><!-->
+ </div>
+ <!--<![endif]-->
+ </div>
+ </div>
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
+ <!--[if (mso)|(IE)]></td></tr></table></td></tr></table><![endif]-->
+ </div>
+ </div>
+ </div>
+ <% end %>
+ <%= render @view_module, @view_template, assigns %>
+
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <!--[if (IE)]></div><![endif]-->
+</body>
+
+</html>
diff --git a/lib/pleroma/web/views/email_view.ex b/lib/pleroma/web/views/email_view.ex
index b506a234b..6b0fbe61e 100644
--- a/lib/pleroma/web/views/email_view.ex
+++ b/lib/pleroma/web/views/email_view.ex
@@ -12,4 +12,8 @@ defmodule Pleroma.Web.EmailView do
|> Timex.parse!("{ISO:Extended:Z}")
|> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}")
end
+
+ def admin_user_url(%{id: id}) do
+ Pleroma.Web.Endpoint.url() <> "/pleroma/admin/#/users/" <> id
+ end
end
diff --git a/lib/pleroma/workers/cron/new_users_digest_worker.ex b/lib/pleroma/workers/cron/new_users_digest_worker.ex
new file mode 100644
index 000000000..951c2c054
--- /dev/null
+++ b/lib/pleroma/workers/cron/new_users_digest_worker.ex
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.Cron.NewUsersDigestWorker do
+ alias Pleroma.Activity
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ import Ecto.Query
+
+ use Pleroma.Workers.WorkerHelper, queue: "new_users_digest"
+
+ @impl Oban.Worker
+ def perform(_args, _job) do
+ if Pleroma.Config.get([Pleroma.Emails.NewUsersDigestEmail, :enabled]) do
+ today = NaiveDateTime.utc_now() |> Timex.beginning_of_day()
+
+ a_day_ago =
+ today
+ |> Timex.shift(days: -1)
+ |> Timex.beginning_of_day()
+
+ users_and_statuses =
+ %{
+ local: true,
+ order_by: :inserted_at
+ }
+ |> User.Query.build()
+ |> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today)
+ |> Repo.all()
+ |> Enum.map(fn user ->
+ latest_status =
+ Activity
+ |> Activity.Queries.by_actor(user.ap_id)
+ |> Activity.Queries.by_type("Create")
+ |> Activity.with_preloaded_object()
+ |> order_by(desc: :inserted_at)
+ |> limit(1)
+ |> Repo.one()
+
+ total_statuses =
+ Activity
+ |> Activity.Queries.by_actor(user.ap_id)
+ |> Activity.Queries.by_type("Create")
+ |> Repo.aggregate(:count, :id)
+
+ {user, total_statuses, latest_status}
+ end)
+
+ if users_and_statuses != [] do
+ %{is_admin: true}
+ |> User.Query.build()
+ |> Repo.all()
+ |> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses))
+ |> Enum.each(&Pleroma.Emails.Mailer.deliver/1)
+ end
+ end
+ end
+end
diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/workers/cron/new_users_digest_worker_test.exs
new file mode 100644
index 000000000..2f439c1fe
--- /dev/null
+++ b/test/workers/cron/new_users_digest_worker_test.exs
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Workers.Cron.NewUsersDigestWorker
+
+ test "it sends new users digest emails" do
+ yesterday = NaiveDateTime.utc_now() |> Timex.shift(days: -1)
+ admin = insert(:user, %{is_admin: true})
+ user = insert(:user, %{inserted_at: yesterday})
+ user2 = insert(:user, %{inserted_at: yesterday})
+ CommonAPI.post(user, %{"status" => "cofe"})
+
+ NewUsersDigestWorker.perform(nil, nil)
+ ObanHelpers.perform_all()
+
+ assert_received {:email, email}
+ assert email.to == [{admin.name, admin.email}]
+ assert email.subject == "#{Pleroma.Config.get([:instance, :name])} New Users"
+
+ refute email.html_body =~ admin.nickname
+ assert email.html_body =~ user.nickname
+ assert email.html_body =~ user2.nickname
+ assert email.html_body =~ "cofe"
+ end
+end