]> git.ipfire.org Git - ipfire.org.git/blob - src/backend/nopaste.py
.gitignore: Add .vscode
[ipfire.org.git] / src / backend / nopaste.py
1 #!/usr/bin/python
2
3 import magic
4
5 from misc import Object
6
7 class Nopaste(Object):
8 def create(self, subject, content, type="text", expires=None, account=None, address=None):
9 self._cleanup_database()
10
11 uid = None
12 if account:
13 uid = account.uid
14
15 # Escape any backslashes. PostgreSQL tends to think that they lead octal
16 # values or something that confuses the convertion from text to bytea.
17 if type == "text":
18 content = content.replace("\\", "\\\\")
19 mimetype = "text/plain"
20
21 elif type == "file":
22 content = buffer(content)
23 mimetype = self._guess_mimetype(content)
24
25 # http://blog.00null.net/easily-generating-random-strings-in-postgresql/
26 res = self.db.get("INSERT INTO nopaste(uuid, subject, content, time_expires, address, \
27 uid, mimetype, size) VALUES(random_slug(), %s, %s, \
28 (CASE WHEN %s = 0 THEN NULL ELSE NOW() + INTERVAL '%s seconds' END), \
29 %s, %s, %s, %s) RETURNING uuid",
30 subject, content, expires, expires, address, uid, mimetype, len(content))
31
32 if res:
33 return res.uuid
34
35 def _guess_mimetype(self, buf):
36 ms = magic.open(magic.NONE)
37 ms.load()
38
39 # Return the mime type
40 ms.setflags(magic.MAGIC_MIME_TYPE)
41
42 buf = "%s" % buf
43
44 try:
45 return ms.buffer(buf)
46 finally:
47 ms.close()
48
49 def get(self, uuid):
50 res = self.db.get("SELECT uuid, subject, time_created, time_expires, address, uid, \
51 mimetype, views, size FROM nopaste WHERE uuid = %s AND (CASE WHEN time_expires \
52 IS NULL THEN TRUE ELSE NOW() < time_expires END)", uuid)
53
54 if res:
55 # Get the account that uploaded this if available
56 res.account = None
57 if res.uid:
58 res.account = self.backend.accounts.get_by_uid(res.uid)
59
60 # Touch the entry so it won't be deleted when it is still used
61 self._update_lastseen(uuid)
62
63 return res
64
65 def get_content(self, uuid):
66 # Try fetching the object from memcache. If found, we return it right away.
67 content = self.memcache.get("nopaste-%s" % uuid)
68
69 # If the object was not in the cache, we need to fetch it from the database.
70 if not content:
71 res = self.db.get("SELECT content, views FROM nopaste WHERE uuid = %s", uuid)
72
73 # Convert the content to a byte string
74 content = "%s" % res.content
75
76 # Save it in the cache for later when it has been requested a couple
77 # of times
78 if res.views >= 5:
79 self.memcache.set("nopaste-%s" % uuid, content, 6 * 3600)
80
81 return content
82
83 def _update_lastseen(self, uuid):
84 self.db.execute("UPDATE nopaste SET time_lastseen = NOW(), views = views + 1 \
85 WHERE uuid = %s", uuid)
86
87 def _cleanup_database(self):
88 # Delete old pastes when they are expired or when they have not been
89 # accessed in a long time.
90 self.db.execute("DELETE FROM nopaste WHERE (CASE \
91 WHEN time_expires IS NULL \
92 THEN time_lastseen + INTERVAL '6 months' <= NOW() \
93 ELSE NOW() >= time_expires END)")