5c9b9400077e7f37cbc371dc9ce136321dd4466a
[anni] / test / pleroma / user / backup_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.User.BackupTest do
6   use Oban.Testing, repo: Pleroma.Repo
7   use Pleroma.DataCase
8
9   import Mock
10   import Pleroma.Factory
11   import Swoosh.TestAssertions
12
13   alias Pleroma.Bookmark
14   alias Pleroma.Tests.ObanHelpers
15   alias Pleroma.User.Backup
16   alias Pleroma.Web.CommonAPI
17   alias Pleroma.Workers.BackupWorker
18
19   setup do
20     clear_config([Pleroma.Upload, :uploader])
21     clear_config([Backup, :limit_days])
22     clear_config([Pleroma.Emails.Mailer, :enabled], true)
23   end
24
25   test "it does not requrie enabled email" do
26     clear_config([Pleroma.Emails.Mailer, :enabled], false)
27     user = insert(:user)
28     assert {:ok, _} = Backup.create(user)
29   end
30
31   test "it does not require user's email" do
32     user = insert(:user, %{email: nil})
33     assert {:ok, _} = Backup.create(user)
34   end
35
36   test "it creates a backup record and an Oban job" do
37     %{id: user_id} = user = insert(:user)
38     assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
39     assert_enqueued(worker: BackupWorker, args: args)
40
41     backup = Backup.get(args["backup_id"])
42     assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
43   end
44
45   test "it return an error if the export limit is over" do
46     %{id: user_id} = user = insert(:user)
47     limit_days = Pleroma.Config.get([Backup, :limit_days])
48     assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
49     backup = Backup.get(args["backup_id"])
50     assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
51
52     assert Backup.create(user) == {:error, "Last export was less than #{limit_days} days ago"}
53   end
54
55   test "it process a backup record" do
56     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
57     %{id: user_id} = user = insert(:user)
58
59     assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
60     assert {:ok, backup} = perform_job(BackupWorker, args)
61     assert backup.file_size > 0
62     assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
63
64     delete_job_args = %{"op" => "delete", "backup_id" => backup_id}
65
66     assert_enqueued(worker: BackupWorker, args: delete_job_args)
67     assert {:ok, backup} = perform_job(BackupWorker, delete_job_args)
68     refute Backup.get(backup_id)
69
70     email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup)
71
72     assert_email_sent(
73       to: {user.name, user.email},
74       html_body: email.html_body
75     )
76   end
77
78   test "it does not send an email if the user does not have an email" do
79     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
80     %{id: user_id} = user = insert(:user, %{email: nil})
81
82     assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
83     assert {:ok, backup} = perform_job(BackupWorker, args)
84     assert backup.file_size > 0
85     assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
86
87     assert_no_email_sent()
88   end
89
90   test "it does not send an email if mailer is not on" do
91     clear_config([Pleroma.Emails.Mailer, :enabled], false)
92     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
93     %{id: user_id} = user = insert(:user)
94
95     assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
96     assert {:ok, backup} = perform_job(BackupWorker, args)
97     assert backup.file_size > 0
98     assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
99
100     assert_no_email_sent()
101   end
102
103   test "it does not send an email if the user has an empty email" do
104     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
105     %{id: user_id} = user = insert(:user, %{email: ""})
106
107     assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
108     assert {:ok, backup} = perform_job(BackupWorker, args)
109     assert backup.file_size > 0
110     assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
111
112     assert_no_email_sent()
113   end
114
115   test "it removes outdated backups after creating a fresh one" do
116     clear_config([Backup, :limit_days], -1)
117     clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
118     user = insert(:user)
119
120     assert {:ok, job1} = Backup.create(user)
121
122     assert {:ok, %Backup{}} = ObanHelpers.perform(job1)
123     assert {:ok, job2} = Backup.create(user)
124     assert Pleroma.Repo.aggregate(Backup, :count) == 2
125     assert {:ok, backup2} = ObanHelpers.perform(job2)
126
127     ObanHelpers.perform_all()
128
129     assert [^backup2] = Pleroma.Repo.all(Backup)
130   end
131
132   test "it creates a zip archive with user data" do
133     user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
134
135     {:ok, %{object: %{data: %{"id" => id1}}} = status1} =
136       CommonAPI.post(user, %{status: "status1"})
137
138     {:ok, %{object: %{data: %{"id" => id2}}} = status2} =
139       CommonAPI.post(user, %{status: "status2"})
140
141     {:ok, %{object: %{data: %{"id" => id3}}} = status3} =
142       CommonAPI.post(user, %{status: "status3"})
143
144     CommonAPI.favorite(user, status1.id)
145     CommonAPI.favorite(user, status2.id)
146
147     Bookmark.create(user.id, status2.id)
148     Bookmark.create(user.id, status3.id)
149
150     assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
151     assert {:ok, path} = Backup.export(backup)
152     assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory])
153     assert {:ok, {'actor.json', json}} = :zip.zip_get('actor.json', zipfile)
154
155     assert %{
156              "@context" => [
157                "https://www.w3.org/ns/activitystreams",
158                "http://localhost:4001/schemas/litepub-0.1.jsonld",
159                %{"@language" => "und"}
160              ],
161              "bookmarks" => "bookmarks.json",
162              "followers" => "http://cofe.io/users/cofe/followers",
163              "following" => "http://cofe.io/users/cofe/following",
164              "id" => "http://cofe.io/users/cofe",
165              "inbox" => "http://cofe.io/users/cofe/inbox",
166              "likes" => "likes.json",
167              "name" => "Cofe",
168              "outbox" => "http://cofe.io/users/cofe/outbox",
169              "preferredUsername" => "cofe",
170              "publicKey" => %{
171                "id" => "http://cofe.io/users/cofe#main-key",
172                "owner" => "http://cofe.io/users/cofe"
173              },
174              "type" => "Person",
175              "url" => "http://cofe.io/users/cofe"
176            } = Jason.decode!(json)
177
178     assert {:ok, {'outbox.json', json}} = :zip.zip_get('outbox.json', zipfile)
179
180     assert %{
181              "@context" => "https://www.w3.org/ns/activitystreams",
182              "id" => "outbox.json",
183              "orderedItems" => [
184                %{
185                  "object" => %{
186                    "actor" => "http://cofe.io/users/cofe",
187                    "content" => "status1",
188                    "type" => "Note"
189                  },
190                  "type" => "Create"
191                },
192                %{
193                  "object" => %{
194                    "actor" => "http://cofe.io/users/cofe",
195                    "content" => "status2"
196                  }
197                },
198                %{
199                  "actor" => "http://cofe.io/users/cofe",
200                  "object" => %{
201                    "content" => "status3"
202                  }
203                }
204              ],
205              "totalItems" => 3,
206              "type" => "OrderedCollection"
207            } = Jason.decode!(json)
208
209     assert {:ok, {'likes.json', json}} = :zip.zip_get('likes.json', zipfile)
210
211     assert %{
212              "@context" => "https://www.w3.org/ns/activitystreams",
213              "id" => "likes.json",
214              "orderedItems" => [^id1, ^id2],
215              "totalItems" => 2,
216              "type" => "OrderedCollection"
217            } = Jason.decode!(json)
218
219     assert {:ok, {'bookmarks.json', json}} = :zip.zip_get('bookmarks.json', zipfile)
220
221     assert %{
222              "@context" => "https://www.w3.org/ns/activitystreams",
223              "id" => "bookmarks.json",
224              "orderedItems" => [^id2, ^id3],
225              "totalItems" => 2,
226              "type" => "OrderedCollection"
227            } = Jason.decode!(json)
228
229     :zip.zip_close(zipfile)
230     File.rm!(path)
231   end
232
233   describe "it uploads and deletes a backup archive" do
234     setup do
235       clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com")
236       clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket")
237
238       user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
239
240       {:ok, status1} = CommonAPI.post(user, %{status: "status1"})
241       {:ok, status2} = CommonAPI.post(user, %{status: "status2"})
242       {:ok, status3} = CommonAPI.post(user, %{status: "status3"})
243       CommonAPI.favorite(user, status1.id)
244       CommonAPI.favorite(user, status2.id)
245       Bookmark.create(user.id, status2.id)
246       Bookmark.create(user.id, status3.id)
247
248       assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
249       assert {:ok, path} = Backup.export(backup)
250
251       [path: path, backup: backup]
252     end
253
254     test "S3", %{path: path, backup: backup} do
255       clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3)
256       clear_config([Pleroma.Uploaders.S3, :streaming_enabled], false)
257
258       with_mock ExAws,
259         request: fn
260           %{http_method: :put} -> {:ok, :ok}
261           %{http_method: :delete} -> {:ok, %{status_code: 204}}
262         end do
263         assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path)
264         assert {:ok, _backup} = Backup.delete(backup)
265       end
266     end
267
268     test "Local", %{path: path, backup: backup} do
269       clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
270
271       assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path)
272       assert {:ok, _backup} = Backup.delete(backup)
273     end
274   end
275 end