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 Approve
Ioana Lasc 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
1diff --git a/lib/lp/registry/model/announcement.py b/lib/lp/registry/model/announcement.py
2index 45b5740..a2c9ac9 100644
3--- a/lib/lp/registry/model/announcement.py
4+++ b/lib/lp/registry/model/announcement.py
5@@ -11,12 +11,21 @@ __all__ = [
6 'MakesAnnouncements',
7 ]
8
9-from sqlobject import (
10- BoolCol,
11- ForeignKey,
12- SQLObjectNotFound,
13- StringCol,
14+import pytz
15+import six
16+from storm.expr import (
17+ And,
18+ LeftJoin,
19+ Or,
20+ Select,
21 )
22+from storm.properties import (
23+ Bool,
24+ DateTime,
25+ Int,
26+ Unicode,
27+ )
28+from storm.references import Reference
29 from zope.interface import implementer
30
31 from lp.registry.interfaces.announcement import (
32@@ -28,40 +37,72 @@ from lp.registry.interfaces.person import validate_public_person
33 from lp.registry.interfaces.product import IProduct
34 from lp.registry.interfaces.projectgroup import IProjectGroup
35 from lp.services.database.constants import UTC_NOW
36-from lp.services.database.datetimecol import UtcDateTimeCol
37-from lp.services.database.sqlbase import (
38- SQLBase,
39- sqlvalues,
40+from lp.services.database.interfaces import (
41+ IMasterStore,
42+ IStore,
43 )
44+from lp.services.database.stormbase import StormBase
45 from lp.services.utils import utc_now
46
47
48 @implementer(IAnnouncement)
49-class Announcement(SQLBase):
50+class Announcement(StormBase):
51 """A news item. These allow us to generate lists of recent news for
52 project groups, products and distributions.
53 """
54
55- _defaultOrder = ['-date_announced', '-date_created']
56-
57- date_created = UtcDateTimeCol(
58- dbName='date_created', notNull=True, default=UTC_NOW)
59- date_announced = UtcDateTimeCol(default=None)
60- date_last_modified = UtcDateTimeCol(
61- dbName='date_updated', default=None)
62- registrant = ForeignKey(
63- dbName='registrant', foreignKey='Person',
64- storm_validator=validate_public_person, notNull=True)
65- product = ForeignKey(dbName='product', foreignKey='Product')
66- projectgroup = ForeignKey(dbName='project', foreignKey='ProjectGroup')
67- distribution = ForeignKey(
68- dbName='distribution', foreignKey='Distribution')
69- title = StringCol(notNull=True)
70- summary = StringCol(default=None)
71- url = StringCol(default=None)
72- active = BoolCol(notNull=True, default=True)
73+ __storm_table__ = 'Announcement'
74+
75+ __storm_order__ = ('-date_announced', '-date_created')
76+
77+ id = Int(primary=True)
78+
79+ date_created = DateTime(allow_none=False, default=UTC_NOW, tzinfo=pytz.UTC)
80+ date_announced = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC)
81+ date_last_modified = DateTime(
82+ name='date_updated', allow_none=True, default=None, tzinfo=pytz.UTC)
83+
84+ registrant_id = Int(
85+ name="registrant", allow_none=False, validator=validate_public_person)
86+ registrant = Reference(registrant_id, "Person.id")
87+
88+ product_id = Int(name="product", allow_none=True, default=None)
89+ product = Reference(product_id, "Product.id")
90+
91+ projectgroup_id = Int(name="project", allow_none=True, default=None)
92+ projectgroup = Reference(projectgroup_id, "ProjectGroup.id")
93+
94+ distribution_id = Int(name="distribution", allow_none=True, default=None)
95+ distribution = Reference(distribution_id, "Distribution.id")
96+
97+ title = Unicode(allow_none=False)
98+ summary = Unicode(allow_none=True, default=None)
99+ url = Unicode(allow_none=True, default=None)
100+ active = Bool(allow_none=False, default=True)
101+
102+ def __init__(self, registrant, title, summary=None, url=None,
103+ active=True, date_created=UTC_NOW, date_announced=None,
104+ date_last_modified=None, product=None, projectgroup=None,
105+ distribution=None):
106+ self.registrant = registrant
107+ self.title = title
108+ self.summary = summary
109+ self.url = url
110+ self.active = active
111+ self.date_created = date_created
112+ self.date_announced = date_announced
113+ self.date_last_modified = date_last_modified
114+ self.product = product
115+ self.projectgroup = projectgroup
116+ self.distribution = distribution
117+
118+ def destroySelf(self):
119+ IMasterStore(self).remove(self)
120
121 def modify(self, title, summary, url):
122+ title = six.text_type(title) if title is not None else None
123+ summary = six.text_type(summary) if summary is not None else None
124+ url = six.text_type(url) if url is not None else None
125 if self.title != title:
126 self.title = title
127 self.date_last_modified = UTC_NOW
128@@ -141,9 +182,8 @@ class HasAnnouncements:
129 announcement_id = int(id)
130 except ValueError:
131 return None
132- try:
133- announcement = Announcement.get(announcement_id)
134- except SQLObjectNotFound:
135+ announcement = IStore(Announcement).get(Announcement, announcement_id)
136+ if announcement is None:
137 return None
138 if announcement.target.name != self.name:
139 return None
140@@ -151,44 +191,43 @@ class HasAnnouncements:
141
142 def getAnnouncements(self, limit=5, published_only=True):
143 """See IHasAnnouncements."""
144+ from lp.registry.model.product import Product
145
146 # Create the SQL query.
147- query = '1=1 '
148+ using = [Announcement]
149+ query = []
150 # Filter for published news items if necessary.
151 if published_only:
152- query += """ AND
153- Announcement.date_announced <= timezone('UTC'::text, now()) AND
154- Announcement.active IS TRUE
155- """
156+ query += [
157+ Announcement.date_announced <= UTC_NOW,
158+ Announcement.active == True]
159 if IProduct.providedBy(self):
160 if self.projectgroup is None:
161- query += """ AND
162- Announcement.product = %s""" % sqlvalues(self.id)
163+ query.append(Announcement.product == self.id)
164 else:
165- query += """ AND
166- (Announcement.product = %s OR Announcement.project = %s)
167- """ % sqlvalues(self.id, self.projectgroup)
168+ query.append(Or(
169+ Announcement.product == self.id,
170+ Announcement.projectgroup == self.projectgroup))
171 elif IProjectGroup.providedBy(self):
172- query += """ AND (
173- Announcement.project = %s
174- OR Announcement.product IN (
175- SELECT id FROM Product
176- WHERE Product.project = %s AND Product.active))
177- """ % sqlvalues(self.id, self.id)
178+ child_products = Select(
179+ Product.id,
180+ And(Product.projectgroup == self, Product.active == True))
181+ query.append(Or(
182+ Announcement.projectgroup == self,
183+ Announcement.product_id.is_in(child_products)))
184 elif IDistribution.providedBy(self):
185- query += (' AND Announcement.distribution = %s'
186- % sqlvalues(self.id))
187+ query.append(Announcement.distribution == self)
188 elif IAnnouncementSet.providedBy(self):
189 # Just filter out inactive projects, mostly to exclude spam.
190- query += """ AND (
191- Announcement.product IS NULL
192- OR EXISTS (
193- SELECT 1 FROM Product WHERE
194- Product.id = Announcement.product AND Product.active))
195- """
196+ using.append(
197+ LeftJoin(Product, Product.id == Announcement.product_id))
198+ query.append(Or(
199+ Announcement.product == None,
200+ Product.active == True))
201 else:
202 raise AssertionError('Unsupported announcement target')
203- return Announcement.select(query, limit=limit)
204+ store = IStore(Announcement)
205+ return store.using(*using).find(Announcement, *query)[:limit]
206
207
208 class MakesAnnouncements(HasAnnouncements):
209@@ -211,13 +250,16 @@ class MakesAnnouncements(HasAnnouncements):
210 # Create the announcement in the database.
211 announcement = Announcement(
212 registrant=user,
213- title=title,
214- summary=summary,
215- url=url,
216+ title=six.text_type(title) if title is not None else None,
217+ summary=six.text_type(summary) if summary is not None else None,
218+ url=six.text_type(url) if url is not None else None,
219 product=product,
220 projectgroup=projectgroup,
221 distribution=distribution,
222 )
223+ store = IMasterStore(Announcement)
224+ store.add(announcement)
225+ store.flush()
226
227 announcement.setPublicationDate(publication_date)
228 return announcement