]>
Commit | Line | Data |
---|---|---|
12e5de7e MT |
1 | #!/usr/bin/python |
2 | ||
9ea64cef | 3 | import datetime |
9fa06206 | 4 | import dateutil |
f0714277 | 5 | import email.utils |
12e5de7e MT |
6 | import tornado.web |
7 | ||
124a8404 | 8 | from . import base |
f91dfcc7 MT |
9 | from . import ui_modules |
10 | ||
da24ac0a | 11 | class IndexHandler(base.BaseHandler): |
8a897d25 | 12 | def get(self): |
feb245e0 | 13 | posts = self.backend.blog.get_newest(limit=10) |
8a897d25 | 14 | |
9d020f28 | 15 | # Allow this to be cached for 5 minutes |
9b8ff27d MT |
16 | if not self.current_user: |
17 | self.set_expires(300) | |
9d020f28 | 18 | |
54b9fef8 RH |
19 | # Extract the latest post |
20 | latest_post = posts.pop(0) | |
21 | ||
22 | self.render("blog/index.html", posts=posts, latest_post=latest_post) | |
8a897d25 MT |
23 | |
24 | ||
da24ac0a | 25 | class AuthorHandler(base.BaseHandler): |
cfc0823a MT |
26 | def get(self, uid): |
27 | author = self.accounts.get_by_uid(uid) | |
28 | if not author: | |
29 | raise tornado.web.HTTPError(404, "User is unknown") | |
30 | ||
31 | # Get all posts from this author | |
cdf85ee7 | 32 | posts = self.backend.blog.get_by_author(author) |
cfc0823a MT |
33 | if not posts: |
34 | raise tornado.web.HTTPError(404, "User has no posts") | |
35 | ||
9d020f28 | 36 | # Allow this to be cached for 10 minutes |
9b8ff27d MT |
37 | if not self.current_user: |
38 | self.set_expires(600) | |
9d020f28 | 39 | |
cfc0823a MT |
40 | self.render("blog/author.html", author=author, posts=posts) |
41 | ||
42 | ||
f0714277 MT |
43 | class FeedHandler(base.BaseHandler): |
44 | def get(self): | |
bc586673 | 45 | posts = self.backend.blog.get_newest(limit=10) |
b2ed0760 MT |
46 | if not posts: |
47 | raise tornado.web.HTTPError(404) | |
f0714277 | 48 | |
9d020f28 MT |
49 | # Allow this to be cached for 10 minutes |
50 | self.set_expires(600) | |
f0714277 MT |
51 | |
52 | # Set correct content type | |
a7d34bc5 | 53 | self.set_header("Content-Type", "application/atom+xml") |
f0714277 | 54 | |
b2ed0760 MT |
55 | # Render the feed |
56 | self.render("blog/feed.xml", posts=posts, | |
a7d34bc5 | 57 | now=datetime.datetime.now()) |
f0714277 MT |
58 | |
59 | ||
da24ac0a | 60 | class PostHandler(base.BaseHandler): |
12e5de7e | 61 | def get(self, slug): |
df157ede | 62 | post = self.backend.blog.get_by_slug(slug, published=not self.current_user) |
0a6875dc | 63 | if not post: |
12e5de7e MT |
64 | raise tornado.web.HTTPError(404) |
65 | ||
9d020f28 | 66 | # Allow this to be cached for 10 minutes |
a864e694 MT |
67 | if post.is_published(): |
68 | self.set_expires(600) | |
9d020f28 | 69 | |
0a6875dc | 70 | self.render("blog/post.html", post=post) |
f91dfcc7 MT |
71 | |
72 | ||
da24ac0a | 73 | class PublishHandler(base.BaseHandler): |
9fa06206 MT |
74 | @tornado.web.authenticated |
75 | def get(self, slug): | |
76 | post = self.backend.blog.get_by_slug(slug, published=False) | |
77 | if not post: | |
78 | raise tornado.web.HTTPError(404) | |
79 | ||
80 | # Check if current_user is allowed to edit the post | |
81 | if not post.is_editable(self.current_user): | |
82 | raise tornado.web.HTTPError(403) | |
83 | ||
84 | # Is the post already published? | |
85 | if post.is_published(): | |
86 | raise tornado.web.HTTPError(400, "Post is already published") | |
87 | ||
88 | self.render("blog/publish.html", post=post) | |
89 | ||
9ea64cef MT |
90 | @tornado.web.authenticated |
91 | def post(self, slug): | |
9fa06206 | 92 | post = self.backend.blog.get_by_slug(slug, published=False) |
9ea64cef MT |
93 | if not post: |
94 | raise tornado.web.HTTPError(404) | |
95 | ||
9fa06206 MT |
96 | # Check if current_user is allowed to edit the post |
97 | if not post.is_editable(self.current_user): | |
98 | raise tornado.web.HTTPError(403) | |
99 | ||
9ea64cef MT |
100 | # Is the post already published? |
101 | if post.is_published(): | |
102 | raise tornado.web.HTTPError(400, "Post is already published") | |
103 | ||
9fa06206 MT |
104 | when = self.get_argument("when", None) |
105 | if when: | |
106 | when = dateutil.parser.parse(when) | |
fe40c0fa | 107 | |
9ea64cef MT |
108 | # Publish the post |
109 | with self.db.transaction(): | |
9fa06206 | 110 | post.publish(when) |
9ea64cef MT |
111 | |
112 | self.redirect("/post/%s" % post.slug) | |
113 | ||
114 | ||
da24ac0a | 115 | class DraftsHandler(base.BaseHandler): |
0b342a05 MT |
116 | @tornado.web.authenticated |
117 | def get(self): | |
118 | drafts = self.backend.blog.get_drafts(author=self.current_user) | |
119 | ||
120 | self.render("blog/drafts.html", drafts=drafts) | |
121 | ||
122 | ||
da24ac0a | 123 | class SearchHandler(base.BaseHandler): |
53a15fe0 | 124 | @base.ratelimit(minutes=5, requests=25) |
e6b18dce MT |
125 | def get(self): |
126 | q = self.get_argument("q") | |
127 | ||
0a6875dc | 128 | posts = self.backend.blog.search(q, limit=50) |
e6b18dce MT |
129 | if not posts: |
130 | raise tornado.web.HTTPError(404, "Nothing found") | |
131 | ||
132 | self.render("blog/search-results.html", q=q, posts=posts) | |
133 | ||
134 | ||
da24ac0a | 135 | class TagHandler(base.BaseHandler): |
4bde7f18 MT |
136 | def get(self, tag): |
137 | posts = self.backend.blog.get_by_tag(tag) | |
138 | if not posts: | |
139 | raise tornado.web.HTTPError(404, "There are no posts with tag: %s" % tag) | |
140 | ||
9d020f28 MT |
141 | # Allow this to be cached for 10 minutes |
142 | self.set_expires(600) | |
143 | ||
f0dc2fc1 | 144 | self.render("blog/tag.html", posts=list(posts), tag=tag) |
4bde7f18 MT |
145 | |
146 | ||
da24ac0a | 147 | class YearHandler(base.BaseHandler): |
7e64f6a3 MT |
148 | def get(self, year): |
149 | posts = self.backend.blog.get_by_year(year) | |
150 | if not posts: | |
151 | raise tornado.web.HTTPError(404, "There are no posts in %s" % year) | |
152 | ||
9d020f28 MT |
153 | # Allow this to be cached for 10 minutes |
154 | self.set_expires(600) | |
155 | ||
7e64f6a3 MT |
156 | self.render("blog/year.html", posts=posts, year=year) |
157 | ||
158 | ||
da24ac0a | 159 | class ComposeHandler(base.BaseHandler): |
541c952b MT |
160 | @tornado.web.authenticated |
161 | def get(self): | |
162 | self.render("blog/compose.html", post=None) | |
163 | ||
164 | @tornado.web.authenticated | |
165 | def post(self): | |
166 | title = self.get_argument("title") | |
167 | text = self.get_argument("text") | |
dc035dce | 168 | tags = self.get_argument("tags", "").split(" ") |
541c952b MT |
169 | |
170 | with self.db.transaction(): | |
171 | post = self.backend.blog.create_post(title, text, | |
172 | author=self.current_user, tags=tags) | |
173 | ||
61e0a831 | 174 | self.redirect("/drafts") |
541c952b MT |
175 | |
176 | ||
da24ac0a | 177 | class EditHandler(base.BaseHandler): |
541c952b MT |
178 | @tornado.web.authenticated |
179 | def get(self, slug): | |
00bf122b | 180 | post = self.backend.blog.get_by_slug(slug, published=False) |
541c952b MT |
181 | if not post: |
182 | raise tornado.web.HTTPError(404) | |
183 | ||
e8a81a70 MT |
184 | # Check if post is editable |
185 | if not post.is_editable(self.current_user): | |
186 | raise tornado.web.HTTPError(403, "%s cannot edit %s" % (self.current_user, post)) | |
541c952b MT |
187 | |
188 | self.render("blog/compose.html", post=post) | |
189 | ||
190 | @tornado.web.authenticated | |
191 | def post(self, slug): | |
00bf122b | 192 | post = self.backend.blog.get_by_slug(slug, published=False) |
541c952b MT |
193 | if not post: |
194 | raise tornado.web.HTTPError(404) | |
195 | ||
e8a81a70 MT |
196 | # Check if post is editable |
197 | if not post.is_editable(self.current_user): | |
198 | raise tornado.web.HTTPError(403, "%s cannot edit %s" % (self.current_user, post)) | |
541c952b | 199 | |
93725180 | 200 | # Save updated content |
541c952b | 201 | with self.db.transaction(): |
93725180 MT |
202 | post.update( |
203 | title = self.get_argument("title"), | |
204 | text = self.get_argument("text"), | |
dc035dce | 205 | tags = self.get_argument("tags", "").split(" "), |
93725180 | 206 | ) |
541c952b MT |
207 | |
208 | # Return to blog if the post is already published | |
209 | if post.is_published(): | |
210 | self.redirect("/post/%s" % post.slug) | |
211 | return | |
212 | ||
61e0a831 MT |
213 | # Otherwise return to drafts |
214 | self.redirect("/drafts") | |
541c952b MT |
215 | |
216 | ||
da24ac0a | 217 | class DeleteHandler(base.BaseHandler): |
914238a5 MT |
218 | @tornado.web.authenticated |
219 | def get(self, slug): | |
220 | post = self.backend.blog.get_by_slug(slug, published=False) | |
221 | if not post: | |
222 | raise tornado.web.HTTPError(404) | |
223 | ||
224 | # Check if post is editable | |
225 | if not post.is_editable(self.current_user): | |
226 | raise tornado.web.HTTPError(403, "%s cannot edit %s" % (self.current_user, post)) | |
227 | ||
228 | self.render("blog/delete.html", post=post) | |
229 | ||
230 | @tornado.web.authenticated | |
231 | def post(self, slug): | |
232 | post = self.backend.blog.get_by_slug(slug, published=False) | |
233 | if not post: | |
234 | raise tornado.web.HTTPError(404) | |
235 | ||
236 | # Check if post is editable | |
237 | if not post.is_editable(self.current_user): | |
238 | raise tornado.web.HTTPError(403, "%s cannot edit %s" % (self.current_user, post)) | |
239 | ||
240 | with self.db.transaction(): | |
241 | post.delete() | |
242 | ||
243 | # Return to drafts | |
244 | self.redirect("/drafts") | |
245 | ||
246 | ||
7e64f6a3 MT |
247 | class HistoryNavigationModule(ui_modules.UIModule): |
248 | def render(self): | |
249 | return self.render_string("blog/modules/history-navigation.html", | |
feb245e0 | 250 | authors=self.backend.blog.authors, years=self.backend.blog.years) |
7e64f6a3 MT |
251 | |
252 | ||
253 | class ListModule(ui_modules.UIModule): | |
feb245e0 MT |
254 | def render(self, posts, relative=False, show_author=True): |
255 | return self.render_string("blog/modules/list.html", | |
256 | posts=posts, relative=relative, show_author=show_author) | |
7e64f6a3 MT |
257 | |
258 | ||
f91dfcc7 MT |
259 | class PostModule(ui_modules.UIModule): |
260 | def render(self, post): | |
261 | return self.render_string("blog/modules/post.html", post=post) |