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