summaryrefslogtreecommitdiff
path: root/quoins/model/blog.py
diff options
context:
space:
mode:
Diffstat (limited to 'quoins/model/blog.py')
-rw-r--r--quoins/model/blog.py261
1 files changed, 261 insertions, 0 deletions
diff --git a/quoins/model/blog.py b/quoins/model/blog.py
new file mode 100644
index 0000000..608a2f1
--- /dev/null
+++ b/quoins/model/blog.py
@@ -0,0 +1,261 @@
1# Quoins - A TurboGears blogging system.
2# Copyright (C) 2008-2009 James E. Blair <corvus@gnu.org>
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from sqlalchemy import *
18from sqlalchemy.orm import mapper, relation
19from sqlalchemy import Table, ForeignKey, Column
20from sqlalchemy.types import Integer, Unicode
21#from sqlalchemy.orm import relation, backref
22import tg
23from datetime import datetime
24
25metadata = tg.config['quoins']['metadata']
26DBSession = tg.config['quoins']['session']
27TGUser = tg.config['quoins']['user']
28
29tguser_table = TGUser.__table__
30
31# Blog schema
32
33blog_table = Table('blog', metadata,
34 Column('id', Integer, primary_key=True),
35 Column('title', Unicode(255)),
36 Column('subtitle', Unicode(255)),
37 Column('allow_comments', Boolean, default=True, nullable=False),
38)
39
40post_table = Table('post', metadata,
41 Column('id', Integer, primary_key=True),
42 Column('blog_id', Integer, ForeignKey('blog.id',
43 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
44 Column('user_id', Integer, ForeignKey(tguser_table.c.user_id,
45 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
46 Column('title', Unicode(255)),
47 Column('teaser', TEXT),
48 Column('body', TEXT),
49 Column('created', DateTime, nullable=False, default=datetime.now),
50 Column('allow_comments', Boolean, nullable=False),
51 Column('published', Boolean, nullable=False, default=False, index=True),
52)
53
54media_table = Table('media', metadata,
55 Column('id', Integer, primary_key=True),
56 Column('post_id', Integer, ForeignKey('post.id',
57 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
58 Column('name', String(255), nullable=False, index=True),
59 Column('mimetype', String(255)),
60 Column('data', BLOB),
61 UniqueConstraint('post_id', 'name'),
62)
63
64tag_table = Table('tag', metadata,
65 Column('id', Integer, primary_key=True),
66 Column('name', Unicode(255)),
67)
68
69post_tag_table = Table('post_tag', metadata,
70 Column('id', Integer, primary_key=True),
71 Column('post_id', Integer, ForeignKey('post.id',
72 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
73 Column('tag_id', Integer, ForeignKey('tag.id',
74 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
75)
76
77comment_table = Table('comment', metadata,
78 Column('id', Integer, primary_key=True),
79 Column('parent_comment_id', Integer, ForeignKey('comment.id',
80 onupdate="CASCADE", ondelete="CASCADE"), index=True),
81 Column('post_id', Integer, ForeignKey('post.id',
82 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
83 Column('user_id', Integer, ForeignKey(tguser_table.c.user_id,
84 onupdate="CASCADE"), index=True),
85 Column('name', Unicode(255)),
86 Column('openid', String(255)),
87 Column('url', String(255)),
88 Column('title', Unicode(255)),
89 Column('body', TEXT),
90 Column('created', DateTime, nullable=False, default=datetime.now),
91 Column('approved', Boolean, nullable=False, default=False, index=True),
92)
93
94linkback_table = Table('linkback', metadata,
95 Column('id', Integer, primary_key=True),
96 Column('post_id', Integer, ForeignKey('post.id',
97 onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True),
98 Column('url', String(255)),
99 Column('title', Unicode(255)),
100 Column('body', Unicode(255)),
101 Column('name', Unicode(255)),
102 Column('created', DateTime, nullable=False, default=datetime.now),
103)
104
105class Blog(object):
106 def get_tags(self):
107 # XXX this assumes that only one blog exists in the schema
108 return DBSession.query(Tag).all()
109 tags = property(get_tags)
110
111 def get_users(self):
112 return [user for user in DBSession.query(TGUser).all() if 'blog-post' in [p.permission_name for p in user.permissions]]
113 authors = property(get_users)
114
115 def getPostsByTag(self, tagname):
116 posts = DBSession.query(Post).filter(and_(post_table.c.blog_id==self.id,
117 post_table.c.id==post_tag_table.c.post_id,
118 post_tag_table.c.tag_id==tag_table.c.id,
119 tag_table.c.name==tagname,
120 post_table.c.published==True)).all()
121 return posts
122
123 def getYears(self):
124 years = {}
125 for p in self.published_posts:
126 x = years.get(p.created.year, 0)
127 years[p.created.year] = x+1
128 years = years.items()
129 years.sort(lambda a,b: cmp(a[0],b[0]))
130 years.reverse()
131 return years
132
133 def getPostsByDate(self, year=None, month=None, day=None):
134 posts = []
135 for p in self.published_posts:
136 if year and p.created.year!=year:
137 continue
138 if month and p.created.month!=month:
139 continue
140 if day and p.created.day!=day:
141 continue
142 posts.append(p)
143 return posts
144
145 def getPostsByAuthor(self, name):
146 posts = []
147 for p in self.published_posts:
148 if p.author.user_name==name:
149 posts.append(p)
150 return posts
151
152
153class Post(object):
154 def get_teaser_or_body(self):
155 if self.teaser: return self.teaser
156 return self.body
157 short_body = property(get_teaser_or_body)
158
159 def get_teaser_and_body(self):
160 if self.teaser:
161 return self.teaser + self.body
162 return self.body
163 long_body = property(get_teaser_and_body)
164
165 def tag(self, name):
166 t = DBSession.query(Tag).filter_by(name=name).first()
167 if not t:
168 t = Tag()
169 DBSession.add(t)
170 t.name = name
171 self.tags.append(t)
172
173 def untag(self, name):
174 t = DBSession.query(Tag).filter_by(name=name).first()
175 if len(t.posts)<2:
176 DBSession.delete(t)
177 self.tags.remove(t)
178
179 def get_comments_and_linkbacks(self, trackbacks=1, pingbacks=1):
180 objects = self.approved_comments[:]
181 for x in self.linkbacks:
182 if (trackbacks and x.body) or (pingbacks and not x.body):
183 objects.append(x)
184 objects.sort(lambda a,b: cmp(a.created, b.created))
185 return objects
186 comments_and_links = property(get_comments_and_linkbacks)
187
188
189class Media(object):
190 pass
191
192class Tag(object):
193 pass
194
195class BaseComment(object):
196 def get_author_name(self):
197 if hasattr(self, 'author') and self.author:
198 return self.author.display_name
199 if self.name:
200 return self.name
201 return 'Anonymous'
202 author_name = property(get_author_name)
203
204 def get_author_url(self):
205 if hasattr(self, 'author') and self.author:
206 return self.author.url
207 if self.url:
208 return self.url
209 return None
210 author_url = property(get_author_url)
211
212class Comment(BaseComment):
213 pass
214
215class LinkBack(BaseComment):
216 pass
217
218mapper(Blog, blog_table,
219 properties=dict(posts=relation(Post,
220 order_by=desc(post_table.c.created)),
221 published_posts=relation(Post,
222 primaryjoin=and_(post_table.c.blog_id==blog_table.c.id,
223 post_table.c.published==True),
224 order_by=desc(post_table.c.created)),
225 unpublished_posts=relation(Post,
226 primaryjoin=and_(post_table.c.blog_id==blog_table.c.id,
227 post_table.c.published==False),
228 order_by=desc(post_table.c.created)),
229 unapproved_comments=relation(Comment, secondary=post_table,
230 primaryjoin=post_table.c.blog_id==blog_table.c.id,
231 secondaryjoin=and_(comment_table.c.post_id==post_table.c.id,
232 comment_table.c.approved==False))))
233
234mapper(Tag, tag_table,
235 order_by=desc(tag_table.c.name))
236
237mapper(Media, media_table,
238 properties=dict(post=relation(Post)))
239
240mapper(Post, post_table,
241 order_by=desc(post_table.c.created),
242 properties=dict(blog=relation(Blog),
243 author=relation(TGUser),
244 tags=relation(Tag, secondary=post_tag_table, backref='posts'),
245 comments=relation(Comment, cascade="all, delete-orphan"),
246 approved_comments=relation(Comment,
247 primaryjoin=and_(comment_table.c.post_id==post_table.c.id,
248 comment_table.c.approved==True)),
249 unapproved_comments=relation(Comment,
250 primaryjoin=and_(comment_table.c.post_id==post_table.c.id,
251 comment_table.c.approved==False)),
252 media=relation(Media),
253 linkbacks=relation(LinkBack)))
254
255mapper(Comment, comment_table,
256 order_by=comment_table.c.created,
257 properties=dict(post=relation(Post),
258 author=relation(TGUser)))
259
260mapper(LinkBack, linkback_table,
261 properties=dict(post=relation(Post)))