]>
Commit | Line | Data |
---|---|---|
66862195 MT |
1 | #!/usr/bin/python |
2 | ||
b0b3e3e7 MT |
3 | import magic |
4 | ||
66862195 MT |
5 | from misc import Object |
6 | ||
7 | class Nopaste(Object): | |
91f4280b | 8 | def create(self, subject, content, type="text", expires=None, account=None, address=None): |
66862195 MT |
9 | self._cleanup_database() |
10 | ||
11 | uid = None | |
12 | if account: | |
13 | uid = account.uid | |
14 | ||
91f4280b MT |
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("\\", "\\\\") | |
b0b3e3e7 MT |
19 | mimetype = "text/plain" |
20 | ||
21 | elif type == "file": | |
22 | content = buffer(content) | |
23 | mimetype = self._guess_mimetype(content) | |
91f4280b | 24 | |
66862195 | 25 | # http://blog.00null.net/easily-generating-random-strings-in-postgresql/ |
b0b3e3e7 MT |
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)) | |
66862195 MT |
31 | |
32 | if res: | |
33 | return res.uuid | |
34 | ||
b0b3e3e7 MT |
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 | ||
66862195 | 49 | def get(self, uuid): |
0de07bc3 MT |
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) | |
66862195 MT |
53 | |
54 | if res: | |
66862195 MT |
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 | ||
0de07bc3 MT |
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: | |
422411da | 71 | res = self.db.get("SELECT content, views FROM nopaste WHERE uuid = %s", uuid) |
0de07bc3 MT |
72 | |
73 | # Convert the content to a byte string | |
74 | content = "%s" % res.content | |
75 | ||
422411da MT |
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) | |
0de07bc3 MT |
80 | |
81 | return content | |
82 | ||
66862195 | 83 | def _update_lastseen(self, uuid): |
bfbf061b | 84 | self.db.execute("UPDATE nopaste SET time_lastseen = NOW(), views = views + 1 \ |
66862195 MT |
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)") |