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

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: d1b4373243ed4d97cccd2e0e78b4f5fd09599821
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:stormify-bugnomination
Merge into: launchpad:master
Diff against target: 287 lines (+98/-48)
7 files modified
lib/lp/bugs/browser/bug.py (+1/-1)
lib/lp/bugs/browser/bugtask.py (+2/-2)
lib/lp/bugs/configure.zcml (+1/-1)
lib/lp/bugs/interfaces/bugnomination.py (+11/-2)
lib/lp/bugs/model/bug.py (+3/-11)
lib/lp/bugs/model/bugnomination.py (+79/-30)
lib/lp/bugs/model/bugtasksearch.py (+1/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+395021@code.launchpad.net

Commit message

Stormifying bug nomination

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

Pushed the requested changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/bugs/browser/bug.py b/lib/lp/bugs/browser/bug.py
2index 61360c9..eedf9b4 100644
3--- a/lib/lp/bugs/browser/bug.py
4+++ b/lib/lp/bugs/browser/bug.py
5@@ -193,7 +193,7 @@ class BugNavigation(Navigation):
6 """Traverse to a nomination by id."""
7 if nomination_id.isdigit():
8 try:
9- return getUtility(IBugNominationSet).get(nomination_id)
10+ return getUtility(IBugNominationSet).get(int(nomination_id))
11 except NotFoundError:
12 return None
13
14diff --git a/lib/lp/bugs/browser/bugtask.py b/lib/lp/bugs/browser/bugtask.py
15index c6bc9d7..5aac3af 100644
16--- a/lib/lp/bugs/browser/bugtask.py
17+++ b/lib/lp/bugs/browser/bugtask.py
18@@ -408,7 +408,7 @@ class BugTaskNavigation(Navigation):
19 """Traverse to a nomination by id."""
20 if not nomination_id.isdigit():
21 return None
22- return getUtility(IBugNominationSet).get(nomination_id)
23+ return getUtility(IBugNominationSet).get(int(nomination_id))
24
25 @redirection('references')
26 def redirect_references(self):
27@@ -1973,7 +1973,7 @@ class BugTasksTableView(LaunchpadView):
28 nominations = list(bug.getNominations())
29 # Eager load validity for all the persons we know of that will be
30 # displayed.
31- ids = set(map(attrgetter('ownerID'), nominations))
32+ ids = set(map(attrgetter('owner_id'), nominations))
33 ids.discard(None)
34 if ids:
35 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
36diff --git a/lib/lp/bugs/configure.zcml b/lib/lp/bugs/configure.zcml
37index 3e4544b..3585d8d 100644
38--- a/lib/lp/bugs/configure.zcml
39+++ b/lib/lp/bugs/configure.zcml
40@@ -802,7 +802,7 @@
41 productseries
42 bug
43 owner
44- ownerID
45+ owner_id
46 decider
47 target
48 status
49diff --git a/lib/lp/bugs/interfaces/bugnomination.py b/lib/lp/bugs/interfaces/bugnomination.py
50index c8ab348..242225d 100644
51--- a/lib/lp/bugs/interfaces/bugnomination.py
52+++ b/lib/lp/bugs/interfaces/bugnomination.py
53@@ -1,4 +1,4 @@
54-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
55+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
56 # GNU Affero General Public License version 3 (see the file LICENSE).
57
58 """Interfaces related to bug nomination."""
59@@ -127,7 +127,7 @@ class IBugNomination(IHasBug, IHasOwner):
60 owner = exported(PublicPersonChoice(
61 title=_('Submitter'), required=True, readonly=True,
62 vocabulary='ValidPersonOrTeam'))
63- ownerID = Attribute('The db id of the owner.')
64+ owner_id = Attribute('The db id of the owner.')
65 decider = exported(PublicPersonChoice(
66 title=_('Decided By'), required=False, readonly=True,
67 vocabulary='ValidPersonOrTeam'))
68@@ -193,6 +193,15 @@ class IBugNominationSet(Interface):
69 nomination was not found.
70 """
71
72+ def getByBugTarget(bug, target):
73+ """Get a nomination by the bug and target.
74+
75+ Returns an IBugNomination, or None if none is found.
76+ """
77+
78+ def findByBug(bug):
79+ """Returns the list of IBugNomination for the given bug."""
80+
81
82 class IBugNominationForm(Interface):
83 """The browser form for nominating bugs for series."""
84diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py
85index 0ca6164..a9b177c 100644
86--- a/lib/lp/bugs/model/bug.py
87+++ b/lib/lp/bugs/model/bug.py
88@@ -127,6 +127,7 @@ from lp.bugs.interfaces.bugattachment import (
89 from lp.bugs.interfaces.bugmessage import IBugMessageSet
90 from lp.bugs.interfaces.bugnomination import (
91 BugNominationStatus,
92+ IBugNominationSet,
93 NominationError,
94 NominationSeriesObsoleteError,
95 )
96@@ -1676,16 +1677,7 @@ class Bug(SQLBase, InformationTypeMixin):
97
98 def getNominationFor(self, target):
99 """See `IBug`."""
100- if IDistroSeries.providedBy(target):
101- filter_args = dict(distroseriesID=target.id)
102- elif IProductSeries.providedBy(target):
103- filter_args = dict(productseriesID=target.id)
104- elif ISourcePackage.providedBy(target):
105- filter_args = dict(distroseriesID=target.series.id)
106- else:
107- return None
108-
109- nomination = BugNomination.selectOneBy(bugID=self.id, **filter_args)
110+ nomination = getUtility(IBugNominationSet).getByBugTarget(self, target)
111
112 if nomination is None:
113 raise NotFoundError(
114@@ -1702,7 +1694,7 @@ class Bug(SQLBase, InformationTypeMixin):
115 return nomination.target.bugtargetdisplayname.lower()
116
117 if nominations is None:
118- nominations = BugNomination.selectBy(bugID=self.id)
119+ nominations = getUtility(IBugNominationSet).findByBug(self)
120 if IProduct.providedBy(target):
121 filtered_nominations = []
122 for nomination in shortlist(nominations):
123diff --git a/lib/lp/bugs/model/bugnomination.py b/lib/lp/bugs/model/bugnomination.py
124index 4c322cd..d44877a 100644
125--- a/lib/lp/bugs/model/bugnomination.py
126+++ b/lib/lp/bugs/model/bugnomination.py
127@@ -1,4 +1,4 @@
128-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
129+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
130 # GNU Affero General Public License version 3 (see the file LICENSE).
131
132 """Database classes related to bug nomination.
133@@ -16,10 +16,11 @@ __all__ = [
134 from datetime import datetime
135
136 import pytz
137-from sqlobject import (
138- ForeignKey,
139- SQLObjectNotFound,
140+from storm.properties import (
141+ DateTime,
142+ Int,
143 )
144+from storm.references import Reference
145 from zope.component import getUtility
146 from zope.interface import implementer
147
148@@ -32,37 +33,61 @@ from lp.bugs.interfaces.bugnomination import (
149 IBugNominationSet,
150 )
151 from lp.bugs.interfaces.bugtask import IBugTaskSet
152+from lp.registry.interfaces.distroseries import IDistroSeries
153 from lp.registry.interfaces.person import validate_public_person
154+from lp.registry.interfaces.productseries import IProductSeries
155+from lp.registry.interfaces.sourcepackage import ISourcePackage
156 from lp.services.database.constants import UTC_NOW
157-from lp.services.database.datetimecol import UtcDateTimeCol
158-from lp.services.database.enumcol import EnumCol
159-from lp.services.database.sqlbase import SQLBase
160+from lp.services.database.enumcol import DBEnum
161+from lp.services.database.interfaces import IStore
162+from lp.services.database.stormbase import StormBase
163 from lp.services.features import getFeatureFlag
164
165
166 @implementer(IBugNomination)
167-class BugNomination(SQLBase):
168- _table = "BugNomination"
169-
170- owner = ForeignKey(
171- dbName='owner', foreignKey='Person',
172- storm_validator=validate_public_person, notNull=True)
173- decider = ForeignKey(
174- dbName='decider', foreignKey='Person',
175- storm_validator=validate_public_person, notNull=False, default=None)
176- date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)
177- date_decided = UtcDateTimeCol(notNull=False, default=None)
178- distroseries = ForeignKey(
179- dbName='distroseries', foreignKey='DistroSeries',
180- notNull=False, default=None)
181- productseries = ForeignKey(
182- dbName='productseries', foreignKey='ProductSeries',
183- notNull=False, default=None)
184- bug = ForeignKey(dbName='bug', foreignKey='Bug', notNull=True)
185- status = EnumCol(
186- dbName='status', notNull=True, schema=BugNominationStatus,
187+class BugNomination(StormBase):
188+
189+ __storm_table__ = "BugNomination"
190+
191+ id = Int(primary=True)
192+
193+ owner_id = Int(
194+ name="owner", allow_none=False, validator=validate_public_person)
195+ owner = Reference(owner_id, "Person.id")
196+
197+ decider_id = Int(
198+ name="decider", allow_none=True, default=None,
199+ validator=validate_public_person)
200+ decider = Reference(decider_id, "Person.id")
201+
202+ date_created = DateTime(allow_none=False, default=UTC_NOW, tzinfo=pytz.UTC)
203+ date_decided = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC)
204+
205+ distroseries_id = Int(name="distroseries", allow_none=True, default=None)
206+ distroseries = Reference(distroseries_id, "DistroSeries.id")
207+
208+ productseries_id = Int(name="productseries", allow_none=True, default=None)
209+ productseries = Reference(productseries_id, "ProductSeries.id")
210+
211+ bug_id = Int(name='bug', allow_none=False)
212+ bug = Reference(bug_id, 'Bug.id')
213+
214+ status = DBEnum(
215+ name='status', allow_none=False, enum=BugNominationStatus,
216 default=BugNominationStatus.PROPOSED)
217
218+ def __init__(self, bug, owner, decider=None, date_created=UTC_NOW,
219+ date_decided=None, distroseries=None,
220+ productseries=None, status=BugNominationStatus.PROPOSED):
221+ self.owner = owner
222+ self.decider = decider
223+ self.date_created = date_created
224+ self.date_decided = date_decided
225+ self.distroseries = distroseries
226+ self.productseries = productseries
227+ self.bug = bug
228+ self.status = status
229+
230 @property
231 def target(self):
232 """See IBugNomination."""
233@@ -156,6 +181,12 @@ class BugNomination(SQLBase):
234 return True
235 return False
236
237+ def destroySelf(self):
238+ IStore(self).remove(self)
239+
240+ def __repr__(self):
241+ return "<BugNomination bug=%s owner=%s>" % (self.bug_id, self.owner_id)
242+
243
244 @implementer(IBugNominationSet)
245 class BugNominationSet:
246@@ -163,7 +194,25 @@ class BugNominationSet:
247
248 def get(self, id):
249 """See IBugNominationSet."""
250- try:
251- return BugNomination.get(id)
252- except SQLObjectNotFound:
253+ store = IStore(BugNomination)
254+ nomination = store.get(BugNomination, id)
255+ if nomination is None:
256 raise NotFoundError(id)
257+ return nomination
258+
259+ def getByBugTarget(self, bug, target):
260+ if IDistroSeries.providedBy(target):
261+ filter_args = dict(distroseries_id=target.id)
262+ elif IProductSeries.providedBy(target):
263+ filter_args = dict(productseries_id=target.id)
264+ elif ISourcePackage.providedBy(target):
265+ filter_args = dict(distroseries_id=target.series.id)
266+ else:
267+ return None
268+ store = IStore(BugNomination)
269+ return store.find(BugNomination, bug=bug, **filter_args).one()
270+
271+ def findByBug(self, bug):
272+ """See IBugNominationSet."""
273+ store = IStore(BugNomination)
274+ return store.find(BugNomination, bug=bug)
275diff --git a/lib/lp/bugs/model/bugtasksearch.py b/lib/lp/bugs/model/bugtasksearch.py
276index 21f7313..184fed4 100644
277--- a/lib/lp/bugs/model/bugtasksearch.py
278+++ b/lib/lp/bugs/model/bugtasksearch.py
279@@ -674,7 +674,7 @@ def _build_query(params):
280 raise AssertionError(
281 'Unknown nomination target: %r.' % params.nominated_for)
282 extra_clauses.append(And(
283- BugNomination.bugID == BugTaskFlat.bug_id,
284+ BugNomination.bug_id == BugTaskFlat.bug_id,
285 BugNomination.status == BugNominationStatus.PROPOSED,
286 target_col == params.nominated_for))
287 clauseTables.append(BugNomination)