-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathfile_message.py
More file actions
143 lines (129 loc) · 5.28 KB
/
file_message.py
File metadata and controls
143 lines (129 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
from .exc import DatabaseUpgradeRequired
import logging
def migrate(conn, *, check_only):
from .. import db
fix_fk = False
if 'message' in db.metadata.tables['files'].c:
if db.engine.name == "sqlite" and db.metadata.tables['files'].c['message'].references(
db.metadata.tables['rooms'].c['id']
):
fix_fk = True
else:
return False
logging.warning("DB migration: adding message/file association")
if check_only:
raise DatabaseUpgradeRequired("Add message/file association")
if db.engine.name == "sqlite" and fix_fk:
# Prior versions of this script created the column referencing rooms(id) instead of
# messages; we need to rewrite the schema to fix it. This schema updating feel janky, but
# is the officially documented method (https://www.sqlite.org/lang_altertable.html)
conn.execute("UPDATE files SET message = NULL")
schema_ver = conn.execute("PRAGMA schema_version").first()[0]
files_sql = conn.execute(
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'files'"
).first()[0]
broken = 'message INTEGER REFERENCES rooms(id)'
fixed = 'message INTEGER REFERENCES messages(id)'
if broken not in files_sql:
raise RuntimeError(
"Didn't find expected schema in files table; cannot proceed with upgrade!"
)
files_sql = files_sql.replace(broken, fixed)
conn.execute("PRAGMA writable_schema=ON")
conn.execute(
"UPDATE sqlite_master SET sql = ? WHERE type = 'table' AND name = 'files'", (files_sql,)
)
conn.execute(f"PRAGMA schema_version={schema_ver+1}")
conn.execute("PRAGMA writable_schema=OFF")
elif db.engine.name == "sqlite":
conn.execute(
"ALTER TABLE files ADD COLUMN message INTEGER REFERENCES messages(id)"
" ON DELETE SET NULL"
)
conn.execute("CREATE INDEX files_message ON files(message)")
conn.execute("DROP TRIGGER IF EXISTS messages_after_delete")
conn.execute(
"""
CREATE TRIGGER messages_after_delete AFTER UPDATE OF data ON messages
FOR EACH ROW WHEN NEW.data IS NULL AND OLD.data IS NOT NULL
BEGIN
-- Unpin if we deleted a pinned message:
DELETE FROM pinned_messages WHERE message = OLD.id;
-- Expire the post's attachments immediately:
UPDATE files SET expiry = 0.0 WHERE message = OLD.id;
END
"""
)
conn.execute("DROP TRIGGER IF EXISTS room_metadata_pinned_add")
conn.execute("DROP TRIGGER IF EXISTS room_metadata_pinned_update")
conn.execute("DROP TRIGGER IF EXISTS room_metadata_pinned_remove")
conn.execute(
"""
CREATE TRIGGER room_metadata_pinned_add AFTER INSERT ON pinned_messages
FOR EACH ROW
BEGIN
UPDATE rooms SET info_updates = info_updates + 1 WHERE id = NEW.room;
UPDATE files SET expiry = NULL WHERE message = NEW.message;
END
"""
)
conn.execute(
"""
CREATE TRIGGER room_metadata_pinned_update AFTER UPDATE ON pinned_messages
FOR EACH ROW
BEGIN
UPDATE rooms SET info_updates = info_updates + 1 WHERE id = NEW.room;
UPDATE files SET expiry = NULL WHERE message = NEW.message;
END
"""
)
conn.execute(
"""
CREATE TRIGGER room_metadata_pinned_remove AFTER DELETE ON pinned_messages
FOR EACH ROW
BEGIN
UPDATE rooms SET info_updates = info_updates + 1 WHERE id = OLD.room;
UPDATE files SET expiry = uploaded + 15.0 * 86400.0 WHERE message = OLD.message;
END
"""
)
else:
conn.execute(
"""
ALTER TABLE files ADD COLUMN message BIGINT REFERENCES messages ON DELETE SET NULL;
CREATE INDEX files_message ON files(message);
DROP TRIGGER IF EXISTS messages_after_delete ON messages;
CREATE OR REPLACE FUNCTION trigger_messages_after_delete()
RETURNS TRIGGER LANGUAGE PLPGSQL AS $$BEGIN
-- Unpin if we deleted a pinned message:
DELETE FROM pinned_messages WHERE message = OLD.id;
-- Expire the posts attachments immediately:
UPDATE files SET expiry = 0.0 WHERE message = OLD.id;
RETURN NULL;
END;$$;
CREATE TRIGGER messages_after_delete AFTER UPDATE OF data ON messages
FOR EACH ROW WHEN (NEW.data IS NULL AND OLD.data IS NOT NULL)
EXECUTE PROCEDURE trigger_messages_after_delete();
DROP TRIGGER IF EXISTS room_metadata_pinned_add ON pinned_messages;
DROP TRIGGER IF EXISTS room_metadata_pinned_remove ON pinned_messages;
CREATE OR REPLACE FUNCTION trigger_room_metadata_pinned_add()
RETURNS TRIGGER LANGUAGE PLPGSQL AS $$BEGIN
UPDATE rooms SET info_updates = info_updates + 1 WHERE id = NEW.room;
UPDATE files SET expiry = NULL WHERE message = NEW.message;
RETURN NULL;
END;$$;
CREATE TRIGGER room_metadata_pinned_add AFTER INSERT OR UPDATE ON pinned_messages
FOR EACH ROW
EXECUTE PROCEDURE trigger_room_metadata_pinned_add();
CREATE OR REPLACE FUNCTION trigger_room_metadata_pinned_remove()
RETURNS TRIGGER LANGUAGE PLPGSQL AS $$BEGIN
UPDATE rooms SET info_updates = info_updates + 1 WHERE id = OLD.room;
UPDATE files SET expiry = uploaded + 15.0*86400.0 WHERE message = OLD.message;
RETURN NULL;
END;$$;
CREATE TRIGGER room_metadata_pinned_remove AFTER DELETE ON pinned_messages
FOR EACH ROW
EXECUTE PROCEDURE trigger_room_metadata_pinned_remove();
"""
)
return True