First
[anni] / test / support / factory.ex
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.Factory do
6   use ExMachina.Ecto, repo: Pleroma.Repo
7
8   require Pleroma.Constants
9
10   alias Pleroma.Object
11   alias Pleroma.User
12
13   @rsa_keys [
14               "test/fixtures/rsa_keys/key_1.pem",
15               "test/fixtures/rsa_keys/key_2.pem",
16               "test/fixtures/rsa_keys/key_3.pem",
17               "test/fixtures/rsa_keys/key_4.pem",
18               "test/fixtures/rsa_keys/key_5.pem"
19             ]
20             |> Enum.map(&File.read!/1)
21
22   def participation_factory do
23     conversation = insert(:conversation)
24     user = insert(:user)
25
26     %Pleroma.Conversation.Participation{
27       conversation: conversation,
28       user: user,
29       read: false
30     }
31   end
32
33   def conversation_factory do
34     %Pleroma.Conversation{
35       ap_id: sequence(:ap_id, &"https://some_conversation/#{&1}")
36     }
37   end
38
39   def user_factory(attrs \\ %{}) do
40     pem = Enum.random(@rsa_keys)
41
42     user = %User{
43       name: sequence(:name, &"Test テスト User #{&1}"),
44       email: sequence(:email, &"user#{&1}@example.com"),
45       nickname: sequence(:nickname, &"nick#{&1}"),
46       password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
47       bio: sequence(:bio, &"Tester Number #{&1}"),
48       is_discoverable: true,
49       last_digest_emailed_at: NaiveDateTime.utc_now(),
50       last_refreshed_at: NaiveDateTime.utc_now(),
51       notification_settings: %Pleroma.User.NotificationSetting{},
52       multi_factor_authentication_settings: %Pleroma.MFA.Settings{},
53       ap_enabled: true,
54       keys: pem
55     }
56
57     urls =
58       if attrs[:local] == false do
59         base_domain = attrs[:domain] || Enum.random(["domain1.com", "domain2.com", "domain3.com"])
60
61         ap_id = "https://#{base_domain}/users/#{user.nickname}"
62
63         %{
64           ap_id: ap_id,
65           follower_address: ap_id <> "/followers",
66           following_address: ap_id <> "/following",
67           featured_address: ap_id <> "/collections/featured"
68         }
69       else
70         %{
71           ap_id: User.ap_id(user),
72           follower_address: User.ap_followers(user),
73           following_address: User.ap_following(user),
74           featured_address: User.ap_featured_collection(user)
75         }
76       end
77
78     attrs = Map.delete(attrs, :domain)
79
80     user
81     |> Map.put(:raw_bio, user.bio)
82     |> Map.merge(urls)
83     |> merge_attributes(attrs)
84   end
85
86   def user_relationship_factory(attrs \\ %{}) do
87     source = attrs[:source] || insert(:user)
88     target = attrs[:target] || insert(:user)
89     relationship_type = attrs[:relationship_type] || :block
90
91     %Pleroma.UserRelationship{
92       source_id: source.id,
93       target_id: target.id,
94       relationship_type: relationship_type
95     }
96   end
97
98   def note_factory(attrs \\ %{}) do
99     text = sequence(:text, &"This is :moominmamma: note #{&1}")
100
101     user = attrs[:user] || insert(:user)
102
103     data = %{
104       "type" => "Note",
105       "content" => text,
106       "source" => text,
107       "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
108       "actor" => user.ap_id,
109       "to" => ["https://www.w3.org/ns/activitystreams#Public"],
110       "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
111       "likes" => [],
112       "like_count" => 0,
113       "context" => "2hu",
114       "summary" => "2hu",
115       "tag" => ["2hu"],
116       "emoji" => %{
117         "2hu" => "corndog.png"
118       }
119     }
120
121     %Pleroma.Object{
122       data: merge_attributes(data, Map.get(attrs, :data, %{}))
123     }
124   end
125
126   def attachment_factory(attrs \\ %{}) do
127     user = attrs[:user] || insert(:user)
128
129     data =
130       attachment_data(user.ap_id, nil)
131       |> Map.put("id", Pleroma.Web.ActivityPub.Utils.generate_object_id())
132
133     %Pleroma.Object{
134       data: merge_attributes(data, Map.get(attrs, :data, %{}))
135     }
136   end
137
138   def attachment_note_factory(attrs \\ %{}) do
139     user = attrs[:user] || insert(:user)
140     {length, attrs} = Map.pop(attrs, :length, 1)
141
142     data = %{
143       "attachment" =>
144         Stream.repeatedly(fn -> attachment_data(user.ap_id, attrs[:href]) end)
145         |> Enum.take(length)
146     }
147
148     build(:note, Map.put(attrs, :data, data))
149   end
150
151   defp attachment_data(ap_id, href) do
152     href = href || sequence(:href, &"#{Pleroma.Web.Endpoint.url()}/media/#{&1}.jpg")
153
154     %{
155       "url" => [
156         %{
157           "href" => href,
158           "type" => "Link",
159           "mediaType" => "image/jpeg"
160         }
161       ],
162       "name" => "some name",
163       "type" => "Document",
164       "actor" => ap_id,
165       "mediaType" => "image/jpeg"
166     }
167   end
168
169   def followers_only_note_factory(attrs \\ %{}) do
170     %Pleroma.Object{data: data} = note_factory(attrs)
171     %Pleroma.Object{data: Map.merge(data, %{"to" => [data["actor"] <> "/followers"]})}
172   end
173
174   def audio_factory(attrs \\ %{}) do
175     text = sequence(:text, &"lain radio episode #{&1}")
176
177     user = attrs[:user] || insert(:user)
178
179     data = %{
180       "type" => "Audio",
181       "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
182       "artist" => "lain",
183       "title" => text,
184       "album" => "lain radio",
185       "to" => ["https://www.w3.org/ns/activitystreams#Public"],
186       "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
187       "actor" => user.ap_id,
188       "length" => 180_000
189     }
190
191     %Pleroma.Object{
192       data: merge_attributes(data, Map.get(attrs, :data, %{}))
193     }
194   end
195
196   def listen_factory do
197     audio = insert(:audio)
198
199     data = %{
200       "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
201       "type" => "Listen",
202       "actor" => audio.data["actor"],
203       "to" => audio.data["to"],
204       "object" => audio.data,
205       "published" => audio.data["published"]
206     }
207
208     %Pleroma.Activity{
209       data: data,
210       actor: data["actor"],
211       recipients: data["to"]
212     }
213   end
214
215   def direct_note_factory do
216     user2 = insert(:user)
217
218     %Pleroma.Object{data: data} = note_factory()
219     %Pleroma.Object{data: Map.merge(data, %{"to" => [user2.ap_id]})}
220   end
221
222   def article_factory do
223     %Pleroma.Object{data: data} = note_factory()
224     %Pleroma.Object{data: Map.merge(data, %{"type" => "Article"})}
225   end
226
227   def tombstone_factory do
228     data = %{
229       "type" => "Tombstone",
230       "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
231       "formerType" => "Note",
232       "deleted" => DateTime.utc_now() |> DateTime.to_iso8601()
233     }
234
235     %Pleroma.Object{
236       data: data
237     }
238   end
239
240   def question_factory(attrs \\ %{}) do
241     user = attrs[:user] || insert(:user)
242
243     data = %{
244       "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
245       "type" => "Question",
246       "actor" => user.ap_id,
247       "attributedTo" => user.ap_id,
248       "attachment" => [],
249       "to" => ["https://www.w3.org/ns/activitystreams#Public"],
250       "cc" => [user.follower_address],
251       "context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
252       "closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
253       "oneOf" => [
254         %{
255           "type" => "Note",
256           "name" => "chocolate",
257           "replies" => %{"totalItems" => 0, "type" => "Collection"}
258         },
259         %{
260           "type" => "Note",
261           "name" => "vanilla",
262           "replies" => %{"totalItems" => 0, "type" => "Collection"}
263         }
264       ]
265     }
266
267     %Pleroma.Object{
268       data: merge_attributes(data, Map.get(attrs, :data, %{}))
269     }
270   end
271
272   def direct_note_activity_factory do
273     dm = insert(:direct_note)
274
275     data = %{
276       "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
277       "type" => "Create",
278       "actor" => dm.data["actor"],
279       "to" => dm.data["to"],
280       "object" => dm.data,
281       "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
282       "context" => dm.data["context"]
283     }
284
285     %Pleroma.Activity{
286       data: data,
287       actor: data["actor"],
288       recipients: data["to"]
289     }
290   end
291
292   def add_activity_factory(attrs \\ %{}) do
293     featured_collection_activity(attrs, "Add")
294   end
295
296   def remove_activity_factor(attrs \\ %{}) do
297     featured_collection_activity(attrs, "Remove")
298   end
299
300   defp featured_collection_activity(attrs, type) do
301     user = attrs[:user] || insert(:user)
302     note = attrs[:note] || insert(:note, user: user)
303
304     data_attrs =
305       attrs
306       |> Map.get(:data_attrs, %{})
307       |> Map.put(:type, type)
308
309     attrs = Map.drop(attrs, [:user, :note, :data_attrs])
310
311     data =
312       %{
313         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
314         "target" => user.featured_address,
315         "object" => note.data["object"],
316         "actor" => note.data["actor"],
317         "type" => "Add",
318         "to" => [Pleroma.Constants.as_public()],
319         "cc" => [user.follower_address]
320       }
321       |> Map.merge(data_attrs)
322
323     %Pleroma.Activity{
324       data: data,
325       actor: data["actor"],
326       recipients: data["to"]
327     }
328     |> Map.merge(attrs)
329   end
330
331   def followers_only_note_activity_factory(attrs \\ %{}) do
332     user = attrs[:user] || insert(:user)
333     note = insert(:followers_only_note, user: user)
334
335     data_attrs = attrs[:data_attrs] || %{}
336     attrs = Map.drop(attrs, [:user, :note, :data_attrs])
337
338     data =
339       %{
340         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
341         "type" => "Create",
342         "actor" => note.data["actor"],
343         "to" => note.data["to"],
344         "object" => note.data,
345         "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
346         "context" => note.data["context"]
347       }
348       |> Map.merge(data_attrs)
349
350     %Pleroma.Activity{
351       data: data,
352       actor: data["actor"],
353       recipients: data["to"]
354     }
355     |> Map.merge(attrs)
356   end
357
358   def note_activity_factory(attrs \\ %{}) do
359     user = attrs[:user] || insert(:user)
360     note = attrs[:note] || insert(:note, user: user)
361
362     data_attrs = attrs[:data_attrs] || %{}
363     attrs = Map.drop(attrs, [:user, :note, :data_attrs])
364
365     data =
366       %{
367         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
368         "type" => "Create",
369         "actor" => note.data["actor"],
370         "to" => note.data["to"],
371         "object" => note.data["id"],
372         "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
373         "context" => note.data["context"]
374       }
375       |> Map.merge(data_attrs)
376
377     %Pleroma.Activity{
378       data: data,
379       actor: data["actor"],
380       recipients: data["to"]
381     }
382     |> Map.merge(attrs)
383   end
384
385   def article_activity_factory do
386     article = insert(:article)
387
388     data = %{
389       "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
390       "type" => "Create",
391       "actor" => article.data["actor"],
392       "to" => article.data["to"],
393       "object" => article.data,
394       "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
395       "context" => article.data["context"]
396     }
397
398     %Pleroma.Activity{
399       data: data,
400       actor: data["actor"],
401       recipients: data["to"]
402     }
403   end
404
405   def announce_activity_factory(attrs \\ %{}) do
406     note_activity = attrs[:note_activity] || insert(:note_activity)
407     user = attrs[:user] || insert(:user)
408
409     data = %{
410       "type" => "Announce",
411       "actor" => note_activity.actor,
412       "object" => note_activity.data["id"],
413       "to" => [user.follower_address, note_activity.data["actor"]],
414       "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
415       "context" => note_activity.data["context"]
416     }
417
418     %Pleroma.Activity{
419       data: data,
420       actor: user.ap_id,
421       recipients: data["to"]
422     }
423   end
424
425   def like_activity_factory(attrs \\ %{}) do
426     note_activity = attrs[:note_activity] || insert(:note_activity)
427     object = Object.normalize(note_activity, fetch: false)
428     user = insert(:user)
429
430     data =
431       %{
432         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
433         "actor" => user.ap_id,
434         "type" => "Like",
435         "object" => object.data["id"],
436         "published_at" => DateTime.utc_now() |> DateTime.to_iso8601()
437       }
438       |> Map.merge(attrs[:data_attrs] || %{})
439
440     %Pleroma.Activity{
441       data: data
442     }
443   end
444
445   def follow_activity_factory do
446     follower = insert(:user)
447     followed = insert(:user)
448
449     data = %{
450       "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
451       "actor" => follower.ap_id,
452       "type" => "Follow",
453       "object" => followed.ap_id,
454       "published_at" => DateTime.utc_now() |> DateTime.to_iso8601()
455     }
456
457     %Pleroma.Activity{
458       data: data,
459       actor: follower.ap_id
460     }
461   end
462
463   def report_activity_factory(attrs \\ %{}) do
464     user = attrs[:user] || insert(:user)
465     activity = attrs[:activity] || insert(:note_activity)
466     state = attrs[:state] || "open"
467
468     data = %{
469       "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
470       "actor" => user.ap_id,
471       "type" => "Flag",
472       "object" => [activity.actor, activity.data["id"]],
473       "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
474       "to" => [],
475       "cc" => [activity.actor],
476       "context" => activity.data["context"],
477       "state" => state
478     }
479
480     %Pleroma.Activity{
481       data: data,
482       actor: data["actor"],
483       recipients: data["to"] ++ data["cc"]
484     }
485   end
486
487   def question_activity_factory(attrs \\ %{}) do
488     user = attrs[:user] || insert(:user)
489     question = attrs[:question] || insert(:question, user: user)
490
491     data_attrs = attrs[:data_attrs] || %{}
492     attrs = Map.drop(attrs, [:user, :question, :data_attrs])
493
494     data =
495       %{
496         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
497         "type" => "Create",
498         "actor" => question.data["actor"],
499         "to" => question.data["to"],
500         "object" => question.data["id"],
501         "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
502         "context" => question.data["context"]
503       }
504       |> Map.merge(data_attrs)
505
506     %Pleroma.Activity{
507       data: data,
508       actor: data["actor"],
509       recipients: data["to"]
510     }
511     |> Map.merge(attrs)
512   end
513
514   def oauth_app_factory do
515     %Pleroma.Web.OAuth.App{
516       client_name: sequence(:client_name, &"Some client #{&1}"),
517       redirect_uris: "https://example.com/callback",
518       scopes: ["read", "write", "follow", "push", "admin"],
519       website: "https://example.com",
520       client_id: Ecto.UUID.generate(),
521       client_secret: "aaa;/&bbb"
522     }
523   end
524
525   def instance_factory do
526     %Pleroma.Instances.Instance{
527       host: "domain.com",
528       unreachable_since: nil
529     }
530   end
531
532   def oauth_token_factory(attrs \\ %{}) do
533     scopes = Map.get(attrs, :scopes, ["read"])
534     oauth_app = Map.get_lazy(attrs, :app, fn -> insert(:oauth_app, scopes: scopes) end)
535     user = Map.get_lazy(attrs, :user, fn -> build(:user) end)
536
537     valid_until =
538       Map.get(attrs, :valid_until, NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10))
539
540     %Pleroma.Web.OAuth.Token{
541       token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
542       refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
543       scopes: scopes,
544       user: user,
545       app: oauth_app,
546       valid_until: valid_until
547     }
548   end
549
550   def oauth_admin_token_factory(attrs \\ %{}) do
551     user = Map.get_lazy(attrs, :user, fn -> build(:user, is_admin: true) end)
552
553     scopes =
554       attrs
555       |> Map.get(:scopes, ["admin"])
556       |> Kernel.++(["admin"])
557       |> Enum.uniq()
558
559     attrs = Map.merge(attrs, %{user: user, scopes: scopes})
560     oauth_token_factory(attrs)
561   end
562
563   def oauth_authorization_factory do
564     %Pleroma.Web.OAuth.Authorization{
565       token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false),
566       scopes: ["read", "write", "follow", "push"],
567       valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10),
568       user: build(:user),
569       app: build(:oauth_app)
570     }
571   end
572
573   def push_subscription_factory do
574     %Pleroma.Web.Push.Subscription{
575       user: build(:user),
576       token: build(:oauth_token),
577       endpoint: "https://example.com/example/1234",
578       key_auth: "8eDyX_uCN0XRhSbY5hs7Hg==",
579       key_p256dh:
580         "BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA=",
581       data: %{}
582     }
583   end
584
585   def notification_factory do
586     %Pleroma.Notification{
587       user: build(:user)
588     }
589   end
590
591   def scheduled_activity_factory do
592     %Pleroma.ScheduledActivity{
593       user: build(:user),
594       scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
595       params: build(:note) |> Map.from_struct() |> Map.get(:data)
596     }
597   end
598
599   def registration_factory do
600     user = insert(:user)
601
602     %Pleroma.Registration{
603       user: user,
604       provider: "twitter",
605       uid: "171799000",
606       info: %{
607         "name" => "John Doe",
608         "email" => "john@doe.com",
609         "nickname" => "johndoe",
610         "description" => "My bio"
611       }
612     }
613   end
614
615   def config_factory(attrs \\ %{}) do
616     %Pleroma.ConfigDB{
617       key: sequence(:key, &String.to_atom("some_key_#{&1}")),
618       group: :pleroma,
619       value:
620         sequence(
621           :value,
622           &%{another_key: "#{&1}somevalue", another: "#{&1}somevalue"}
623         )
624     }
625     |> merge_attributes(attrs)
626   end
627
628   def marker_factory do
629     %Pleroma.Marker{
630       user: build(:user),
631       timeline: "notifications",
632       lock_version: 0,
633       last_read_id: "1"
634     }
635   end
636
637   def mfa_token_factory do
638     %Pleroma.MFA.Token{
639       token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false),
640       authorization: build(:oauth_authorization),
641       valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10),
642       user: build(:user)
643     }
644   end
645
646   def filter_factory do
647     %Pleroma.Filter{
648       user: build(:user),
649       filter_id: sequence(:filter_id, & &1),
650       phrase: "cofe",
651       context: ["home"]
652     }
653   end
654
655   def announcement_factory(params \\ %{}) do
656     data = Map.get(params, :data, %{})
657
658     {_, params} = Map.pop(params, :data)
659
660     %Pleroma.Announcement{
661       data: Map.merge(%{"content" => "test announcement", "all_day" => false}, data)
662     }
663     |> Map.merge(params)
664     |> Pleroma.Announcement.add_rendered_properties()
665   end
666 end