From f08241c8ab1b1f920e6c2d179fc1086b0ad10c1d Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sat, 7 May 2022 00:20:50 -0400
Subject: [PATCH] Allow users to create backups without providing email address

Ref: backup-without-email
---
 lib/pleroma/user/backup.ex                    | 18 +-------
 lib/pleroma/workers/backup_worker.ex          | 24 ++++++++--
 test/pleroma/user/backup_test.exs             | 45 +++++++++++++++++--
 .../controllers/backup_controller_test.exs    | 20 +++++++++
 4 files changed, 82 insertions(+), 25 deletions(-)

diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index cba94248f..2c6378265 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -32,9 +32,7 @@ defmodule Pleroma.User.Backup do
   end
 
   def create(user, admin_id \\ nil) do
-    with :ok <- validate_email_enabled(),
-         :ok <- validate_user_email(user),
-         :ok <- validate_limit(user, admin_id),
+    with :ok <- validate_limit(user, admin_id),
          {:ok, backup} <- user |> new() |> Repo.insert() do
       BackupWorker.process(backup, admin_id)
     end
@@ -86,20 +84,6 @@ defp validate_limit(user, nil) do
     end
   end
 
-  defp validate_email_enabled do
-    if Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled]) do
-      :ok
-    else
-      {:error, dgettext("errors", "Backups require enabled email")}
-    end
-  end
-
-  defp validate_user_email(%User{email: nil}) do
-    {:error, dgettext("errors", "Email is required")}
-  end
-
-  defp validate_user_email(%User{email: email}) when is_binary(email), do: :ok
-
   def get_last(user_id) do
     __MODULE__
     |> where(user_id: ^user_id)
diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex
index 9b763b04b..66c5c3591 100644
--- a/lib/pleroma/workers/backup_worker.ex
+++ b/lib/pleroma/workers/backup_worker.ex
@@ -37,10 +37,7 @@ def perform(%Job{
            backup_id |> Backup.get() |> Backup.process(),
          {:ok, _job} <- schedule_deletion(backup),
          :ok <- Backup.remove_outdated(backup),
-         {:ok, _} <-
-           backup
-           |> Pleroma.Emails.UserEmail.backup_is_ready_email(admin_user_id)
-           |> Pleroma.Emails.Mailer.deliver() do
+         :ok <- maybe_deliver_email(backup, admin_user_id) do
       {:ok, backup}
     end
   end
@@ -51,4 +48,23 @@ def perform(%Job{args: %{"op" => "delete", "backup_id" => backup_id}}) do
       nil -> :ok
     end
   end
+
+  defp has_email?(user) do
+    not is_nil(user.email) and user.email != ""
+  end
+
+  defp maybe_deliver_email(backup, admin_user_id) do
+    has_mailer = Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled])
+    backup = backup |> Pleroma.Repo.preload(:user)
+
+    if has_email?(backup.user) and has_mailer do
+      backup
+      |> Pleroma.Emails.UserEmail.backup_is_ready_email(admin_user_id)
+      |> Pleroma.Emails.Mailer.deliver()
+
+      :ok
+    else
+      :ok
+    end
+  end
 end
diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs
index b16152876..029bbbf56 100644
--- a/test/pleroma/user/backup_test.exs
+++ b/test/pleroma/user/backup_test.exs
@@ -22,15 +22,15 @@ defmodule Pleroma.User.BackupTest do
     clear_config([Pleroma.Emails.Mailer, :enabled], true)
   end
 
-  test "it requries enabled email" do
+  test "it does not requrie enabled email" do
     clear_config([Pleroma.Emails.Mailer, :enabled], false)
     user = insert(:user)
-    assert {:error, "Backups require enabled email"} == Backup.create(user)
+    assert {:ok, _} = Backup.create(user)
   end
 
-  test "it requries user's email" do
+  test "it does not require user's email" do
     user = insert(:user, %{email: nil})
-    assert {:error, "Email is required"} == Backup.create(user)
+    assert {:ok, _} = Backup.create(user)
   end
 
   test "it creates a backup record and an Oban job" do
@@ -75,6 +75,43 @@ test "it process a backup record" do
     )
   end
 
+  test "it does not send an email if the user does not have an email" do
+    clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+    %{id: user_id} = user = insert(:user, %{email: nil})
+
+    assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
+    assert {:ok, backup} = perform_job(BackupWorker, args)
+    assert backup.file_size > 0
+    assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
+
+    assert_no_email_sent()
+  end
+
+  test "it does not send an email if mailer is not on" do
+    clear_config([Pleroma.Emails.Mailer, :enabled], false)
+    clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+    %{id: user_id} = user = insert(:user)
+
+    assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
+    assert {:ok, backup} = perform_job(BackupWorker, args)
+    assert backup.file_size > 0
+    assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
+
+    assert_no_email_sent()
+  end
+
+  test "it does not send an email if the user has an empty email" do
+    clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+    %{id: user_id} = user = insert(:user, %{email: ""})
+
+    assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
+    assert {:ok, backup} = perform_job(BackupWorker, args)
+    assert backup.file_size > 0
+    assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
+
+    assert_no_email_sent()
+  end
+
   test "it removes outdated backups after creating a fresh one" do
     clear_config([Backup, :limit_days], -1)
     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
diff --git a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs
index 3ee660a05..ba17636da 100644
--- a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs
@@ -82,4 +82,24 @@ test "POST /api/v1/pleroma/backups", %{user: _user, conn: conn} do
              |> post("/api/v1/pleroma/backups")
              |> json_response_and_validate_schema(400)
   end
+
+  test "Backup without email address" do
+    user = Pleroma.Factory.insert(:user, email: nil)
+    %{conn: conn} = oauth_access(["read:accounts"], user: user)
+
+    assert is_nil(user.email)
+
+    assert [
+             %{
+               "content_type" => "application/zip",
+               "url" => _url,
+               "file_size" => 0,
+               "processed" => false,
+               "inserted_at" => _
+             }
+           ] =
+             conn
+             |> post("/api/v1/pleroma/backups")
+             |> json_response_and_validate_schema(:ok)
+  end
 end