Merge branch 'conversation-pagination' into 'develop'
[akkoma] / lib / mix / tasks / pleroma / database.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Mix.Tasks.Pleroma.Database do
6 alias Pleroma.Conversation
7 alias Pleroma.Maintenance
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.User
11 require Logger
12 require Pleroma.Constants
13 import Mix.Pleroma
14 use Mix.Task
15
16 @shortdoc "A collection of database related tasks"
17 @moduledoc File.read!("docs/administration/CLI_tasks/database.md")
18
19 def run(["remove_embedded_objects" | args]) do
20 {options, [], []} =
21 OptionParser.parse(
22 args,
23 strict: [
24 vacuum: :boolean
25 ]
26 )
27
28 start_pleroma()
29 Logger.info("Removing embedded objects")
30
31 Repo.query!(
32 "update activities set data = safe_jsonb_set(data, '{object}'::text[], data->'object'->'id') where data->'object'->>'id' is not null;",
33 [],
34 timeout: :infinity
35 )
36
37 if Keyword.get(options, :vacuum) do
38 Maintenance.vacuum("full")
39 end
40 end
41
42 def run(["bump_all_conversations"]) do
43 start_pleroma()
44 Conversation.bump_for_all_activities()
45 end
46
47 def run(["update_users_following_followers_counts"]) do
48 start_pleroma()
49
50 User
51 |> Repo.all()
52 |> Enum.each(&User.update_follower_count/1)
53 end
54
55 def run(["prune_objects" | args]) do
56 import Ecto.Query
57
58 {options, [], []} =
59 OptionParser.parse(
60 args,
61 strict: [
62 vacuum: :boolean
63 ]
64 )
65
66 start_pleroma()
67
68 deadline = Pleroma.Config.get([:instance, :remote_post_retention_days])
69
70 Logger.info("Pruning objects older than #{deadline} days")
71
72 time_deadline =
73 NaiveDateTime.utc_now()
74 |> NaiveDateTime.add(-(deadline * 86_400))
75
76 from(o in Object,
77 where:
78 fragment(
79 "?->'to' \\? ? OR ?->'cc' \\? ?",
80 o.data,
81 ^Pleroma.Constants.as_public(),
82 o.data,
83 ^Pleroma.Constants.as_public()
84 ),
85 where: o.inserted_at < ^time_deadline,
86 where:
87 fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
88 )
89 |> Repo.delete_all(timeout: :infinity)
90
91 if Keyword.get(options, :vacuum) do
92 Maintenance.vacuum("full")
93 end
94 end
95
96 def run(["fix_likes_collections"]) do
97 import Ecto.Query
98
99 start_pleroma()
100
101 from(object in Object,
102 where: fragment("(?)->>'likes' is not null", object.data),
103 select: %{id: object.id, likes: fragment("(?)->>'likes'", object.data)}
104 )
105 |> Pleroma.RepoStreamer.chunk_stream(100)
106 |> Stream.each(fn objects ->
107 ids =
108 objects
109 |> Enum.filter(fn object -> object.likes |> Jason.decode!() |> is_map() end)
110 |> Enum.map(& &1.id)
111
112 Object
113 |> where([object], object.id in ^ids)
114 |> update([object],
115 set: [
116 data:
117 fragment(
118 "safe_jsonb_set(?, '{likes}', '[]'::jsonb, true)",
119 object.data
120 )
121 ]
122 )
123 |> Repo.update_all([], timeout: :infinity)
124 end)
125 |> Stream.run()
126 end
127
128 def run(["vacuum", args]) do
129 start_pleroma()
130
131 Maintenance.vacuum(args)
132 end
133 end