]> git.ipfire.org Git - ipfire.org.git/blob - src/backend/nopaste.py
nopaste: Store blobs in a separate table
[ipfire.org.git] / src / backend / nopaste.py
1 #!/usr/bin/python3
2
3 import datetime
4 import magic
5
6 from .misc import Object
7
8 class Nopaste(Object):
9 def create(self, content, subject=None, mimetype=None, expires=None, account=None, address=None):
10 self._cleanup_database()
11
12 # Store the blob
13 blob_id = self._store_blob(content)
14
15 # Guess the mimetype if none set
16 if not mimetype:
17 mimetype = magic.from_buffer(content, mime=True)
18
19 uid = None
20 if account:
21 uid = account.uid
22
23 if expires:
24 expires = datetime.datetime.utcnow() + datetime.timedelta(seconds=expires)
25
26 # http://blog.00null.net/easily-generating-random-strings-in-postgresql/
27 res = self.db.get("""
28 INSERT INTO
29 nopaste
30 (
31 uuid,
32 subject,
33 content,
34 time_expires,
35 address,
36 uid,
37 mimetype,
38 size,
39 blob_id
40 )
41 VALUES
42 (
43 random_slug(), %s, %s, %s, %s, %s, %s, %s, %s
44 )
45 RETURNING
46 uuid
47 """, subject, content, expires or None, address, uid, mimetype, len(content), blob_id,
48 )
49
50 if res:
51 return res.uuid
52
53 def _store_blob(self, data):
54 """
55 Stores the blob by sending it to the database and returning its ID
56 """
57 blob = self.db.get("""
58 INSERT INTO
59 nopaste_blobs
60 (
61 data
62 )
63 VALUES
64 (
65 %s
66 )
67 ON CONFLICT
68 (
69 data
70 )
71 DO UPDATE SET
72 last_uploaded_at = CURRENT_TIMESTAMP
73 RETURNING
74 id
75 """, data
76 )
77
78 # Return the ID
79 return blob.id
80
81 def get(self, uuid):
82 res = self.db.get("SELECT uuid, subject, time_created, time_expires, address, uid, \
83 mimetype, views, size FROM nopaste WHERE uuid = %s AND (CASE WHEN time_expires \
84 IS NULL THEN TRUE ELSE NOW() < time_expires END)", uuid)
85
86 if res:
87 # Get the account that uploaded this if available
88 res.account = None
89 if res.uid:
90 res.account = self.backend.accounts.get_by_uid(res.uid)
91
92 # Touch the entry so it won't be deleted when it is still used
93 self._update_lastseen(uuid)
94
95 return res
96
97 def get_content(self, uuid):
98 res = self.db.get("SELECT content FROM nopaste \
99 WHERE uuid = %s", uuid)
100
101 if res:
102 return bytes(res.content)
103
104 def _update_lastseen(self, uuid):
105 self.db.execute("UPDATE nopaste SET time_lastseen = NOW(), views = views + 1 \
106 WHERE uuid = %s", uuid)
107
108 def _cleanup_database(self):
109 # Delete old pastes when they are expired or when they have not been
110 # accessed in a long time.
111 self.db.execute("DELETE FROM nopaste WHERE (CASE \
112 WHEN time_expires IS NULL \
113 THEN time_lastseen + INTERVAL '6 months' <= NOW() \
114 ELSE NOW() >= time_expires END)")