Merge branch 'refactor/use-constants' into 'develop'
[akkoma] / lib / mix / tasks / pleroma / database.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 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 @moduledoc """
17 A collection of database related tasks
18
19 ## Replace embedded objects with their references
20
21 Replaces embedded objects with references to them in the `objects` table. Only needs to be ran once. The reason why this is not a migration is because it could significantly increase the database size after being ran, however after this `VACUUM FULL` will be able to reclaim about 20% (really depends on what is in the database, your mileage may vary) of the db size before the migration.
22
23 mix pleroma.database remove_embedded_objects
24
25 Options:
26 - `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references
27
28 ## Prune old objects from the database
29
30 mix pleroma.database prune_objects
31
32 ## Create a conversation for all existing DMs. Can be safely re-run.
33
34 mix pleroma.database bump_all_conversations
35
36 ## Remove duplicated items from following and update followers count for all users
37
38 mix pleroma.database update_users_following_followers_counts
39 """
40 def run(["remove_embedded_objects" | args]) do
41 {options, [], []} =
42 OptionParser.parse(
43 args,
44 strict: [
45 vacuum: :boolean
46 ]
47 )
48
49 start_pleroma()
50 Logger.info("Removing embedded objects")
51
52 Repo.query!(
53 "update activities set data = jsonb_set(data, '{object}'::text[], data->'object'->'id') where data->'object'->>'id' is not null;",
54 [],
55 timeout: :infinity
56 )
57
58 if Keyword.get(options, :vacuum) do
59 Logger.info("Runnning VACUUM FULL")
60
61 Repo.query!(
62 "vacuum full;",
63 [],
64 timeout: :infinity
65 )
66 end
67 end
68
69 def run(["bump_all_conversations"]) do
70 start_pleroma()
71 Conversation.bump_for_all_activities()
72 end
73
74 def run(["update_users_following_followers_counts"]) do
75 start_pleroma()
76
77 users = Repo.all(User)
78 Enum.each(users, &User.remove_duplicated_following/1)
79 Enum.each(users, &User.update_follower_count/1)
80 end
81
82 def run(["prune_objects" | args]) do
83 import Ecto.Query
84
85 {options, [], []} =
86 OptionParser.parse(
87 args,
88 strict: [
89 vacuum: :boolean
90 ]
91 )
92
93 start_pleroma()
94
95 deadline = Pleroma.Config.get([:instance, :remote_post_retention_days])
96
97 Logger.info("Pruning objects older than #{deadline} days")
98
99 time_deadline =
100 NaiveDateTime.utc_now()
101 |> NaiveDateTime.add(-(deadline * 86_400))
102
103 from(o in Object,
104 where:
105 fragment(
106 "?->'to' \\? ? OR ?->'cc' \\? ?",
107 o.data,
108 ^Pleroma.Constants.as_public(),
109 o.data,
110 ^Pleroma.Constants.as_public()
111 ),
112 where: o.inserted_at < ^time_deadline,
113 where:
114 fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
115 )
116 |> Repo.delete_all(timeout: :infinity)
117
118 if Keyword.get(options, :vacuum) do
119 Logger.info("Runnning VACUUM FULL")
120
121 Repo.query!(
122 "vacuum full;",
123 [],
124 timeout: :infinity
125 )
126 end
127 end
128 end