Merge ~pappacena/launchpad:stormify-announcement into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: eea0222fe32d2c4a30d5fe20a808f6620713f306
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:stormify-announcement
Merge into: launchpad:master
Diff against target: 228 lines (+101/-59)
1 file modified
lib/lp/registry/model/announcement.py (+101/-59)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Ioana Lasc (community) Approve
Review via email: mp+395106@code.launchpad.net

Commit message

Converting Announcements to Storm

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) wrote :

looks good

review: Approve
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/registry/model/announcement.py b/lib/lp/registry/model/announcement.py
index 45b5740..a2c9ac9 100644
--- a/lib/lp/registry/model/announcement.py
+++ b/lib/lp/registry/model/announcement.py
@@ -11,12 +11,21 @@ __all__ = [
11 'MakesAnnouncements',11 'MakesAnnouncements',
12 ]12 ]
1313
14from sqlobject import (14import pytz
15 BoolCol,15import six
16 ForeignKey,16from storm.expr import (
17 SQLObjectNotFound,17 And,
18 StringCol,18 LeftJoin,
19 Or,
20 Select,
19 )21 )
22from storm.properties import (
23 Bool,
24 DateTime,
25 Int,
26 Unicode,
27 )
28from storm.references import Reference
20from zope.interface import implementer29from zope.interface import implementer
2130
22from lp.registry.interfaces.announcement import (31from lp.registry.interfaces.announcement import (
@@ -28,40 +37,72 @@ from lp.registry.interfaces.person import validate_public_person
28from lp.registry.interfaces.product import IProduct37from lp.registry.interfaces.product import IProduct
29from lp.registry.interfaces.projectgroup import IProjectGroup38from lp.registry.interfaces.projectgroup import IProjectGroup
30from lp.services.database.constants import UTC_NOW39from lp.services.database.constants import UTC_NOW
31from lp.services.database.datetimecol import UtcDateTimeCol40from lp.services.database.interfaces import (
32from lp.services.database.sqlbase import (41 IMasterStore,
33 SQLBase,42 IStore,
34 sqlvalues,
35 )43 )
44from lp.services.database.stormbase import StormBase
36from lp.services.utils import utc_now45from lp.services.utils import utc_now
3746
3847
39@implementer(IAnnouncement)48@implementer(IAnnouncement)
40class Announcement(SQLBase):49class Announcement(StormBase):
41 """A news item. These allow us to generate lists of recent news for50 """A news item. These allow us to generate lists of recent news for
42 project groups, products and distributions.51 project groups, products and distributions.
43 """52 """
4453
45 _defaultOrder = ['-date_announced', '-date_created']54 __storm_table__ = 'Announcement'
4655
47 date_created = UtcDateTimeCol(56 __storm_order__ = ('-date_announced', '-date_created')
48 dbName='date_created', notNull=True, default=UTC_NOW)57
49 date_announced = UtcDateTimeCol(default=None)58 id = Int(primary=True)
50 date_last_modified = UtcDateTimeCol(59
51 dbName='date_updated', default=None)60 date_created = DateTime(allow_none=False, default=UTC_NOW, tzinfo=pytz.UTC)
52 registrant = ForeignKey(61 date_announced = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC)
53 dbName='registrant', foreignKey='Person',62 date_last_modified = DateTime(
54 storm_validator=validate_public_person, notNull=True)63 name='date_updated', allow_none=True, default=None, tzinfo=pytz.UTC)
55 product = ForeignKey(dbName='product', foreignKey='Product')64
56 projectgroup = ForeignKey(dbName='project', foreignKey='ProjectGroup')65 registrant_id = Int(
57 distribution = ForeignKey(66 name="registrant", allow_none=False, validator=validate_public_person)
58 dbName='distribution', foreignKey='Distribution')67 registrant = Reference(registrant_id, "Person.id")
59 title = StringCol(notNull=True)68
60 summary = StringCol(default=None)69 product_id = Int(name="product", allow_none=True, default=None)
61 url = StringCol(default=None)70 product = Reference(product_id, "Product.id")
62 active = BoolCol(notNull=True, default=True)71
72 projectgroup_id = Int(name="project", allow_none=True, default=None)
73 projectgroup = Reference(projectgroup_id, "ProjectGroup.id")
74
75 distribution_id = Int(name="distribution", allow_none=True, default=None)
76 distribution = Reference(distribution_id, "Distribution.id")
77
78 title = Unicode(allow_none=False)
79 summary = Unicode(allow_none=True, default=None)
80 url = Unicode(allow_none=True, default=None)
81 active = Bool(allow_none=False, default=True)
82
83 def __init__(self, registrant, title, summary=None, url=None,
84 active=True, date_created=UTC_NOW, date_announced=None,
85 date_last_modified=None, product=None, projectgroup=None,
86 distribution=None):
87 self.registrant = registrant
88 self.title = title
89 self.summary = summary
90 self.url = url
91 self.active = active
92 self.date_created = date_created
93 self.date_announced = date_announced
94 self.date_last_modified = date_last_modified
95 self.product = product
96 self.projectgroup = projectgroup
97 self.distribution = distribution
98
99 def destroySelf(self):
100 IMasterStore(self).remove(self)
63101
64 def modify(self, title, summary, url):102 def modify(self, title, summary, url):
103 title = six.text_type(title) if title is not None else None
104 summary = six.text_type(summary) if summary is not None else None
105 url = six.text_type(url) if url is not None else None
65 if self.title != title:106 if self.title != title:
66 self.title = title107 self.title = title
67 self.date_last_modified = UTC_NOW108 self.date_last_modified = UTC_NOW
@@ -141,9 +182,8 @@ class HasAnnouncements:
141 announcement_id = int(id)182 announcement_id = int(id)
142 except ValueError:183 except ValueError:
143 return None184 return None
144 try:185 announcement = IStore(Announcement).get(Announcement, announcement_id)
145 announcement = Announcement.get(announcement_id)186 if announcement is None:
146 except SQLObjectNotFound:
147 return None187 return None
148 if announcement.target.name != self.name:188 if announcement.target.name != self.name:
149 return None189 return None
@@ -151,44 +191,43 @@ class HasAnnouncements:
151191
152 def getAnnouncements(self, limit=5, published_only=True):192 def getAnnouncements(self, limit=5, published_only=True):
153 """See IHasAnnouncements."""193 """See IHasAnnouncements."""
194 from lp.registry.model.product import Product
154195
155 # Create the SQL query.196 # Create the SQL query.
156 query = '1=1 '197 using = [Announcement]
198 query = []
157 # Filter for published news items if necessary.199 # Filter for published news items if necessary.
158 if published_only:200 if published_only:
159 query += """ AND201 query += [
160 Announcement.date_announced <= timezone('UTC'::text, now()) AND202 Announcement.date_announced <= UTC_NOW,
161 Announcement.active IS TRUE203 Announcement.active == True]
162 """
163 if IProduct.providedBy(self):204 if IProduct.providedBy(self):
164 if self.projectgroup is None:205 if self.projectgroup is None:
165 query += """ AND206 query.append(Announcement.product == self.id)
166 Announcement.product = %s""" % sqlvalues(self.id)
167 else:207 else:
168 query += """ AND208 query.append(Or(
169 (Announcement.product = %s OR Announcement.project = %s)209 Announcement.product == self.id,
170 """ % sqlvalues(self.id, self.projectgroup)210 Announcement.projectgroup == self.projectgroup))
171 elif IProjectGroup.providedBy(self):211 elif IProjectGroup.providedBy(self):
172 query += """ AND (212 child_products = Select(
173 Announcement.project = %s213 Product.id,
174 OR Announcement.product IN (214 And(Product.projectgroup == self, Product.active == True))
175 SELECT id FROM Product215 query.append(Or(
176 WHERE Product.project = %s AND Product.active))216 Announcement.projectgroup == self,
177 """ % sqlvalues(self.id, self.id)217 Announcement.product_id.is_in(child_products)))
178 elif IDistribution.providedBy(self):218 elif IDistribution.providedBy(self):
179 query += (' AND Announcement.distribution = %s'219 query.append(Announcement.distribution == self)
180 % sqlvalues(self.id))
181 elif IAnnouncementSet.providedBy(self):220 elif IAnnouncementSet.providedBy(self):
182 # Just filter out inactive projects, mostly to exclude spam.221 # Just filter out inactive projects, mostly to exclude spam.
183 query += """ AND (222 using.append(
184 Announcement.product IS NULL223 LeftJoin(Product, Product.id == Announcement.product_id))
185 OR EXISTS (224 query.append(Or(
186 SELECT 1 FROM Product WHERE225 Announcement.product == None,
187 Product.id = Announcement.product AND Product.active))226 Product.active == True))
188 """
189 else:227 else:
190 raise AssertionError('Unsupported announcement target')228 raise AssertionError('Unsupported announcement target')
191 return Announcement.select(query, limit=limit)229 store = IStore(Announcement)
230 return store.using(*using).find(Announcement, *query)[:limit]
192231
193232
194class MakesAnnouncements(HasAnnouncements):233class MakesAnnouncements(HasAnnouncements):
@@ -211,13 +250,16 @@ class MakesAnnouncements(HasAnnouncements):
211 # Create the announcement in the database.250 # Create the announcement in the database.
212 announcement = Announcement(251 announcement = Announcement(
213 registrant=user,252 registrant=user,
214 title=title,253 title=six.text_type(title) if title is not None else None,
215 summary=summary,254 summary=six.text_type(summary) if summary is not None else None,
216 url=url,255 url=six.text_type(url) if url is not None else None,
217 product=product,256 product=product,
218 projectgroup=projectgroup,257 projectgroup=projectgroup,
219 distribution=distribution,258 distribution=distribution,
220 )259 )
260 store = IMasterStore(Announcement)
261 store.add(announcement)
262 store.flush()
221263
222 announcement.setPublicationDate(publication_date)264 announcement.setPublicationDate(publication_date)
223 return announcement265 return announcement