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