202
212
from lp.registry.model.pillar import pillar_sort_key
203
213
from lp.registry.model.teammembership import TeamParticipation
214
from lp.services.database.stormbase import StormBase
204
215
from lp.services.fields import DuplicateBug
205
216
from lp.services.propertycache import (
521
532
parent = message_by_id.get(parent.id, parent)
523
534
message, bugmessage = row
524
parent = None # parent attribute is not going to be accessed.
535
parent = None # parent attribute is not going to be accessed.
525
536
index = bugmessage.index
526
537
result = IndexedMessage(message, inside, index, parent)
527
538
if include_parents:
843
854
"""See `IBug`."""
844
855
return self.personIsSubscribedToDuplicate(person)
857
def _getMutes(self, person):
858
store = Store.of(self)
862
BugMute.person == person)
846
865
def isMuted(self, person):
847
866
"""See `IBug`."""
848
store = Store.of(self)
849
subscriptions = store.find(
851
BugSubscription.bug == self,
852
BugSubscription.person == person,
853
BugSubscription.bug_notification_level ==
854
BugNotificationLevel.NOTHING)
855
return not subscriptions.is_empty()
867
mutes = self._getMutes(person)
868
return not mutes.is_empty()
857
870
def mute(self, person, muted_by):
858
871
"""See `IBug`."""
859
872
if person is None:
860
873
# This may be a webservice request.
861
874
person = muted_by
862
# If there's an existing subscription, update it.
863
store = Store.of(self)
864
subscriptions = store.find(
866
BugSubscription.bug == self,
867
BugSubscription.person == person)
868
if subscriptions.is_empty():
869
return self.subscribe(
870
person, muted_by, level=BugNotificationLevel.NOTHING)
875
assert not person.is_team, (
876
"Muting a subscription for entire team is not allowed.")
878
# If it's already muted, ignore the request.
879
mutes = self._getMutes(person)
881
mute = BugMute(person, self)
882
Store.of(mute).flush()
872
subscription = subscriptions.one()
873
subscription.bug_notification_level = (
874
BugNotificationLevel.NOTHING)
884
# It's already muted, pass.
877
887
def unmute(self, person, unmuted_by):
878
888
"""See `IBug`."""
879
self.unsubscribe(person, unmuted_by)
889
store = Store.of(self)
891
# This may be a webservice request.
893
mutes = self._getMutes(person)
894
store.remove(mutes.one())
895
return self.getSubscriptionForPerson(person)
882
898
def subscriptions(self):
888
904
BugSubscription.bug_id == self.id).order_by(BugSubscription.id)
889
905
return DecoratedResultSet(results, operator.itemgetter(1))
891
def getSubscriptionInfo(self, level=BugNotificationLevel.NOTHING):
907
def getSubscriptionInfo(self, level=BugNotificationLevel.LIFECYCLE):
892
908
"""See `IBug`."""
893
909
return BugSubscriptionInfo(self, level)
907
923
if level is None:
908
level = BugNotificationLevel.NOTHING
924
level = BugNotificationLevel.LIFECYCLE
909
925
subscriptions = self.getSubscriptionInfo(level).direct_subscriptions
910
926
if recipients is not None:
911
927
for subscriber in subscriptions.subscribers:
2235
2251
return IStore(BugSubscription).find(
2236
2252
BugSubscription,
2237
2253
BugSubscription.bug_notification_level >= self.level,
2238
BugSubscription.bug == self.bug)
2254
BugSubscription.bug == self.bug,
2255
Not(In(BugSubscription.person_id,
2256
Select(BugMute.person_id, BugMute.bug_id==self.bug.id))))
2240
2258
@cachedproperty
2241
2259
@freeze(BugSubscriptionSet)
2248
2266
BugSubscription,
2249
2267
BugSubscription.bug_notification_level >= self.level,
2250
2268
BugSubscription.bug_id == Bug.id,
2251
Bug.duplicateof == self.bug)
2269
Bug.duplicateof == self.bug,
2270
Not(In(BugSubscription.person_id,
2271
Select(BugMute.person_id, BugMute.bug_id==Bug.id))))
2253
2273
@cachedproperty
2254
2274
@freeze(BugSubscriptionSet)
2255
2275
def duplicate_only_subscriptions(self):
2256
"""Subscripitions to duplicates of the bug.
2276
"""Subscriptions to duplicates of the bug.
2258
2278
Excludes subscriptions for people who have a direct subscription or
2259
2279
are also notified for another reason.
2294
2314
if self.bug.private:
2295
2315
return BugSubscriberSet()
2317
muted = IStore(BugMute).find(
2319
BugMute.person_id==Person.id,
2320
BugMute.bug==self.bug)
2297
2321
return BugSubscriberSet().union(
2298
2322
self.structural_subscriptions.subscribers,
2299
2323
self.all_pillar_owners_without_bug_supervisors,
2300
2324
self.all_assignees).difference(
2301
self.direct_subscriptions.subscribers)
2325
self.direct_subscriptions.subscribers).difference(muted)
2303
2327
@cachedproperty
2304
2328
def indirect_subscribers(self):
2637
2661
def asDict(self):
2638
2662
"""Return the FileBugData instance as a dict."""
2639
2663
return self.__dict__.copy()
2666
class BugMute(StormBase):
2667
"""Contains bugs a person has decided to block notifications from."""
2669
implements(IBugMute)
2671
__storm_table__ = "BugMute"
2673
def __init__(self, person=None, bug=None):
2674
if person is not None:
2675
self.person = person
2677
self.bug_id = bug.id
2679
person_id = Int("person", allow_none=False, validator=validate_person)
2680
person = Reference(person_id, "Person.id")
2682
bug_id = Int("bug", allow_none=False)
2683
bug = Reference(bug_id, "Bug.id")
2685
__storm_primary__ = 'person_id', 'bug_id'
2687
date_created = DateTime(
2688
"date_created", allow_none=False, default=UTC_NOW,