def test_representation(self):
     with admin_logged_in():
         faq = self.factory.makeFAQ(title="Nothing works")
         with notify_modified(faq, ['keywords', 'content'], user=faq.owner):
             faq.keywords = "foo bar"
             faq.content = "It is all broken."
         faq_url = api_url(faq)
     webservice = webservice_for_person(self.factory.makePerson())
     repr = webservice.get(faq_url, api_version='devel').jsonBody()
     with admin_logged_in():
         self.assertThat(
             repr,
             ContainsDict({
                 "id":
                 Equals(faq.id),
                 "title":
                 Equals("Nothing works"),
                 "keywords":
                 Equals("foo bar"),
                 "content":
                 Equals("It is all broken."),
                 "date_created":
                 MatchesRegex("\d\d\d\d-\d\d-\d\dT.*"),
                 "date_last_updated":
                 MatchesRegex("\d\d\d\d-\d\d-\d\dT.*"),
                 "last_updated_by_link":
                 Contains("/devel/~%s" % faq.owner.name),
                 "target_link":
                 Contains("/devel/%s" % faq.target.name),
             }))
Пример #2
0
    def test_workitems_added_notification_message(self):
        """ Test that we get a notification for setting work items on a new
        specification."""
        stub.test_emails = []
        spec = self.factory.makeSpecification()
        # For API requests, lazr.restful does the notification; for this
        # test we need to call ourselves.
        with notify_modified(spec, ['workitems_text']):
            new_work_item = {
                'title': 'A work item',
                'status': SpecificationWorkItemStatus.TODO,
                'assignee': None,
                'milestone': None,
                'sequence': 0
            }
            login_person(spec.owner)
            spec.updateWorkItems([new_work_item])
        transaction.commit()

        self.assertEqual(1, len(stub.test_emails))
        rationale = 'Work items set to:\nWork items:\n%s: %s' % (
            new_work_item['title'], new_work_item['status'].name)
        [email] = stub.test_emails
        # Actual message is part 2 of the email.
        msg = email[2]
        self.assertIn(rationale, msg)
Пример #3
0
 def test_activity_rule_changed(self):
     owner = self.factory.makeTeam()
     member = self.factory.makePerson(member_of=[owner])
     repository = self.factory.makeGitRepository(owner=owner)
     rule = self.factory.makeGitRule(repository=repository,
                                     ref_pattern="refs/heads/*")
     with person_logged_in(member):
         with notify_modified(rule, ["ref_pattern"]):
             rule.ref_pattern = "refs/heads/other/*"
     self.assertThat(
         repository.getActivity().first(),
         MatchesStructure(repository=Equals(repository),
                          changer=Equals(member),
                          changee=Is(None),
                          what_changed=Equals(GitActivityType.RULE_CHANGED),
                          old_value=MatchesDict({
                              "ref_pattern":
                              Equals("refs/heads/*"),
                              "position":
                              Equals(0),
                          }),
                          new_value=MatchesDict({
                              "ref_pattern":
                              Equals("refs/heads/other/*"),
                              "position":
                              Equals(0),
                          })))
Пример #4
0
    def setGrants(self, grants, user):
        """See `IGitRule`."""
        self._validateGrants(grants)
        existing_grants = {(grant.grantee_type, grant.grantee): grant
                           for grant in self.grants}
        new_grants = OrderedDict(
            ((grant.grantee_type, grant.grantee), grant) for grant in grants)

        for grant_key, grant in existing_grants.items():
            if grant_key not in new_grants:
                grant.destroySelf(user)

        for grant_key, new_grant in new_grants.items():
            grant = existing_grants.get(grant_key)
            if grant is None:
                new_grantee = (new_grant.grantee if new_grant.grantee_type
                               == GitGranteeType.PERSON else
                               new_grant.grantee_type)
                grant = self.addGrant(new_grantee,
                                      user,
                                      can_create=new_grant.can_create,
                                      can_push=new_grant.can_push,
                                      can_force_push=new_grant.can_force_push)
            else:
                edited_fields = []
                with notify_modified(grant, edited_fields):
                    for field in ("can_create", "can_push", "can_force_push"):
                        if getattr(grant, field) != getattr(new_grant, field):
                            setattr(grant, field, getattr(new_grant, field))
                            edited_fields.append(field)
Пример #5
0
 def test_modifiedevent_sets_date_last_modified(self):
     # When a LiveFS receives an object modified event, the last modified
     # date is set to UTC_NOW.
     livefs = self.factory.makeLiveFS(
         date_created=datetime(2014, 4, 25, 10, 38, 0, tzinfo=pytz.UTC))
     with notify_modified(removeSecurityProxy(livefs), ["name"]):
         pass
     self.assertSqlAttributeEqualsDate(livefs, "date_last_modified",
                                       UTC_NOW)
Пример #6
0
 def test_duplicate_edit_notifications(self):
     # Bug edits for a duplicate are sent to duplicate subscribers only.
     with notify_modified(self.dupe_bug, ['description'],
                          user=self.dupe_bug.owner):
         self.dupe_bug.description = 'A changed description'
     latest_notification = BugNotification.selectFirst(orderBy='-id')
     recipients = set(recipient.person
                      for recipient in latest_notification.recipients)
     self.assertEqual(self.dupe_subscribers, recipients)
Пример #7
0
 def test_notifications_for_question_subscribers(self):
     # Ensure that notifications are sent to subscribers of a
     # question linked to the expired bug.
     bugtask = self.bug.default_bugtask
     with notify_modified(bugtask, ["status"]):
         bugtask.transitionToStatus(BugTaskStatus.EXPIRED,
                                    self.product.owner)
     recipients = [
         job.metadata['recipient_set'] for job in pop_questionemailjobs()
     ]
     self.assertContentEqual(['ASKER_SUBSCRIBER'], recipients)
Пример #8
0
 def test_modifiedevent_sets_date_last_modified(self):
     # When a Webhook receives an object modified event, the last modified
     # date is set to UTC_NOW.
     webhook = self.factory.makeWebhook()
     transaction.commit()
     with admin_logged_in():
         old_mtime = webhook.date_last_modified
     with notify_modified(webhook, ['delivery_url']):
         pass
     with admin_logged_in():
         self.assertThat(webhook.date_last_modified, GreaterThan(old_mtime))
Пример #9
0
 def test_change_rule(self):
     repository = self.factory.makeGitRepository()
     rule = self.factory.makeGitRule(
         repository=repository, ref_pattern="refs/heads/foo")
     transaction.commit()
     snapshot = Snapshot(repository, providing=providedBy(repository))
     with person_logged_in(repository.owner):
         with notify_modified(rule, ["ref_pattern"]):
             rule.ref_pattern = "refs/heads/bar"
     self.assertDeltaDescriptionEqual(
         [], ["Changed protected ref: refs/heads/foo => refs/heads/bar"],
         snapshot, repository)
    def test_modifyPOTemplate_makes_job(self):
        """Creating a Packaging should make a TranslationMergeJob."""
        potemplate = self.factory.makePOTemplate()
        finder = JobFinder(None, None, TranslationTemplateChangeJob,
                           potemplate)
        self.assertEqual([], finder.find())
        with person_logged_in(potemplate.owner):
            with notify_modified(potemplate, ["name"]):
                potemplate.name = self.factory.getUniqueString()

        (job, ) = finder.find()
        self.assertIsInstance(job, TranslationTemplateChangeJob)
Пример #11
0
 def test_assignee_new_subscriber(self):
     """Build a list of people who will receive emails about the bug
     task changes and ensure the assignee is not one."""
     with notify_modified(self.bug_task, ['assignee'], user=self.user):
         self.bug_task.transitionToAssignee(self.person_assigned)
     latest_notification = BugNotification.selectFirst(orderBy='-id')
     notifications, omitted, messages = construct_email_notifications(
         [latest_notification])
     self.assertEqual(len(notifications), 1, 'email notication not created')
     receivers = [message['To'] for message in messages]
     self.assertFalse(self.person_assigned_email in receivers,
                      'Assignee was emailed about the bug task change')
Пример #12
0
 def test_assignee_notification_message(self):
     """Test notification string when a person is assigned a task by
        someone else."""
     self.assertEqual(len(stub.test_emails), 0, 'emails in queue')
     with notify_modified(self.bug_task, ['assignee'], user=self.user):
         self.bug_task.transitionToAssignee(self.person_assigned)
     transaction.commit()
     self.assertEqual(len(stub.test_emails), 1, 'email not sent')
     rationale = (
         'Sample Person (name12) has assigned this bug to you for Rebirth')
     msg = stub.test_emails[-1][2]
     self.assertTrue(rationale in msg, '%s not in\n%s\n' % (rationale, msg))
Пример #13
0
 def test_assignee_not_a_subscriber(self):
     """Test that a new recipient being assigned a bug task does send
        a NEW message."""
     self.assertEqual(len(stub.test_emails), 0, 'emails in queue')
     with notify_modified(self.bug_task, ['assignee'], user=self.user):
         self.bug_task.transitionToAssignee(self.person_assigned)
     transaction.commit()
     self.assertEqual(len(stub.test_emails), 1, 'email not sent')
     new_message = '[NEW]'
     msg = stub.test_emails[-1][2]
     self.assertTrue(new_message in msg,
                     '%s not in \n%s\n' % (new_message, msg))
Пример #14
0
 def test_self_assignee_notification_message(self):
     """Test notification string when a person is assigned a task by
        themselves."""
     stub.test_emails = []
     with notify_modified(self.bug_task, ['assignee']):
         self.bug_task.transitionToAssignee(self.user)
     transaction.commit()
     self.assertEqual(1, len(stub.test_emails))
     rationale = ('You have assigned this bug to yourself for Rebirth')
     [email] = stub.test_emails
     # Actual message is part 2 of the email.
     msg = email[2]
     self.assertIn(rationale, msg)
 def test_for_bug_modifier_header(self):
     """Test X-Launchpad-Bug-Modifier appears when a bug is modified."""
     with notify_modified(self.bug_task, ['status'], user=self.user):
         self.bug_task.transitionToStatus(BugTaskStatus.CONFIRMED,
                                          self.user)
     transaction.commit()
     latest_notification = BugNotification.selectFirst(orderBy='-id')
     notifications, omitted, messages = construct_email_notifications(
         [latest_notification])
     self.assertEqual(len(notifications), 1,
                      'email notification not created')
     headers = [msg['X-Launchpad-Bug-Modifier'] for msg in messages]
     self.assertEqual(len(headers), len(messages))
Пример #16
0
 def test_team_assigned_new_subscriber(self):
     """Assign a team, who is not subscribed to a bug, a bug task and
     ensure that team members do not receive an email about the bug
     task changes."""
     with notify_modified(self.bug_task, ['assignee'], user=self.user):
         self.bug_task.transitionToAssignee(self.team_assigned)
     latest_notification = BugNotification.selectFirst(orderBy='-id')
     notifications, omitted, messages = construct_email_notifications(
         [latest_notification])
     self.assertEqual(len(notifications), 1,
                      'email notification not created')
     receivers = [message['To'] for message in messages]
     self.assertFalse(self.team_member_email in receivers,
                      'Team member was emailed about the bug task change')
Пример #17
0
    def create_action(self, action, data):
        """Create a Bug from a Question."""
        question = self.context

        with notify_modified(question, ['bugs']):
            params = CreateBugParams(owner=self.user,
                                     title=data['title'],
                                     comment=data['description'])
            bug = question.target.createBug(params)
            question.linkBug(bug, user=self.user)
            bug.subscribe(question.owner, self.user)
        self.request.response.addNotification(
            _('Thank you! Bug #$bugid created.', mapping={'bugid': bug.id}))
        self.next_url = canonical_url(bug)
 def test_dup_subscriber_change_notification_message(self):
     """Duplicate bug number in the reason (email footer) for
        duplicate subscribers when a master bug is modified."""
     with notify_modified(self.master_bug_task, ['status'], user=self.user):
         self.master_bug_task.transitionToStatus(
             BugTaskStatus.CONFIRMED, self.user)
     transaction.commit()
     latest_notification = BugNotification.selectFirst(orderBy='-id')
     notifications, omitted, messages = construct_email_notifications(
         [latest_notification])
     self.assertEqual(
         len(notifications), 1, 'email notification not created')
     rationale = 'duplicate bug report (%i)' % self.dup_bug.id
     self.assertIn(rationale, str(messages[-1]))
Пример #19
0
    def _setAndNotifyDateActivated(self):
        """Set the date_activated field and fire a
        SQLObjectModified event.

        The date_activated field is only set once - repeated calls
        will not change the field's value.

        Similarly, the modification event only fires the first time
        that the field is set.
        """
        if self.date_activated is not None:
            return

        with notify_modified(self, ['date_activated']):
            self.date_activated = UTC_NOW
Пример #20
0
 def test_change_grant(self):
     repository = self.factory.makeGitRepository()
     grant = self.factory.makeGitRuleGrant(
         repository=repository, ref_pattern="refs/heads/*",
         can_create=True)
     transaction.commit()
     snapshot = Snapshot(repository, providing=providedBy(repository))
     with person_logged_in(repository.owner):
         with notify_modified(grant, ["can_push"]):
             grant.can_push = True
     self.assertDeltaDescriptionEqual(
         [],
         ["Changed access for ~{grantee} to refs/heads/*: "
          "create => create and push".format(grantee=grant.grantee.name)],
         snapshot, repository)
Пример #21
0
    def expireBugTasks(self, transaction_manager):
        """Expire old, unassigned, Incomplete BugTasks.

        Only BugTasks for projects that use Malone are updated. This method
        will login as the bug_watch_updater celebrity and logout after the
        expiration is done.
        """
        message_template = ('[Expired for %s because there has been no '
                            'activity for %d days.]')
        self.log.info('Expiring unattended, INCOMPLETE bugtasks older than '
                      '%d days for projects that use Launchpad Bugs.' %
                      self.days_before_expiration)
        self._login()
        try:
            expired_count = 0
            bugtask_set = getUtility(IBugTaskSet)
            incomplete_bugtasks = bugtask_set.findExpirableBugTasks(
                self.days_before_expiration,
                user=self.janitor,
                target=self.target,
                limit=self.limit)
            self.log.info('Found %d bugtasks to expire.' %
                          incomplete_bugtasks.count())
            for bugtask in incomplete_bugtasks:
                # We don't expire bugtasks with conjoined masters.
                if bugtask.conjoined_master:
                    continue

                with notify_modified(bugtask, ['status'], user=self.janitor):
                    bugtask.transitionToStatus(BugTaskStatus.EXPIRED,
                                               self.janitor)
                    content = message_template % (bugtask.bugtargetdisplayname,
                                                  self.days_before_expiration)
                    bugtask.bug.newMessage(
                        owner=self.janitor,
                        subject=bugtask.bug.followup_subject(),
                        content=content)
                # We commit after each expiration because emails are sent
                # immediately in zopeless. This minimize the risk of
                # duplicate expiration emails being sent in case an error
                # occurs later on.
                transaction_manager.commit()
                expired_count += 1
            self.log.info('Expired %d bugtasks.' % expired_count)
        finally:
            self._logout()
        self.log.info('Finished expiration run.')
Пример #22
0
 def test_generates_notification(self):
     obj = Thing(0)
     with EventRecorder() as recorder:
         with notify_modified(obj, ["attr"]):
             obj.attr = 1
     self.assertThat(
         recorder.events,
         MatchesListwise([
             MatchesAll(
                 Provides(IObjectModifiedEvent),
                 MatchesStructure(
                     object=MatchesStructure(attr=Equals(1)),
                     object_before_modification=MatchesAll(
                         Provides(IThing),
                         MatchesStructure(attr=Equals(0))),
                     edited_fields=Equals(["attr"]),
                     user=Provides(IUnauthenticatedPrincipal))),
         ]))
Пример #23
0
 def test_different_user(self):
     obj = Thing(0)
     user = self.factory.makePerson()
     with EventRecorder() as recorder:
         with notify_modified(obj, ["attr"], user=user):
             obj.attr = 1
     self.assertThat(
         recorder.events,
         MatchesListwise([
             MatchesAll(
                 Provides(IObjectModifiedEvent),
                 MatchesStructure(object=MatchesStructure(attr=Equals(1)),
                                  object_before_modification=MatchesAll(
                                      Provides(IThing),
                                      MatchesStructure(attr=Equals(0))),
                                  edited_fields=Equals(["attr"]),
                                  user=Equals(user))),
         ]))
Пример #24
0
    def test_workitems_deleted_notification_message(self):
        """ Test that we get a notification for deleting a work item."""
        stub.test_emails = []
        wi = self.factory.makeSpecificationWorkItem()
        spec = wi.specification
        # In production this notification is fired by lazr.restful, but we
        # need to do it ourselves in this test.
        with notify_modified(spec, ['workitems_text']):
            login_person(spec.owner)
            spec.updateWorkItems([])
        transaction.commit()

        self.assertEqual(1, len(stub.test_emails))
        rationale = '- %s: %s' % (wi.title, wi.status.name)
        [email] = stub.test_emails
        # Actual message is part 2 of the email.
        msg = email[2]
        self.assertIn(rationale, msg)
Пример #25
0
 def test_activity_grant_changed(self):
     owner = self.factory.makeTeam()
     member = self.factory.makePerson(member_of=[owner])
     repository = self.factory.makeGitRepository(owner=owner)
     grant = self.factory.makeGitRuleGrant(
         repository=repository,
         grantee=GitGranteeType.REPOSITORY_OWNER,
         can_create=True)
     with person_logged_in(member):
         with notify_modified(grant, ["can_create", "can_force_push"]):
             grant.can_create = False
             grant.can_force_push = True
     self.assertThat(
         repository.getActivity().first(),
         MatchesStructure(repository=Equals(repository),
                          changer=Equals(member),
                          changee=Is(None),
                          what_changed=Equals(
                              GitActivityType.GRANT_CHANGED),
                          old_value=MatchesDict({
                              "changee_type":
                              Equals("Repository owner"),
                              "ref_pattern":
                              Equals("refs/heads/*"),
                              "can_create":
                              Is(True),
                              "can_push":
                              Is(False),
                              "can_force_push":
                              Is(False),
                          }),
                          new_value=MatchesDict({
                              "changee_type":
                              Equals("Repository owner"),
                              "ref_pattern":
                              Equals("refs/heads/*"),
                              "can_create":
                              Is(False),
                              "can_push":
                              Is(False),
                              "can_force_push":
                              Is(True),
                          })))
Пример #26
0
 def test_mutate_edited_fields_within_block(self):
     obj = Thing(0)
     with EventRecorder() as recorder:
         edited_fields = set()
         with notify_modified(obj, edited_fields):
             obj.attr = 1
             edited_fields.add("attr")
     self.assertThat(
         recorder.events,
         MatchesListwise([
             MatchesAll(
                 Provides(IObjectModifiedEvent),
                 MatchesStructure(
                     object=MatchesStructure(attr=Equals(1)),
                     object_before_modification=MatchesAll(
                         Provides(IThing),
                         MatchesStructure(attr=Equals(0))),
                     edited_fields=Equals(["attr"]),
                     user=Provides(IUnauthenticatedPrincipal))),
         ]))
Пример #27
0
    def test_workitems_changed_notification_message(self):
        """ Test that we get a notification about a work item status change.
        This will be in the form of a line added and one deleted."""
        spec = self.factory.makeSpecification()
        original_status = SpecificationWorkItemStatus.TODO
        new_status = SpecificationWorkItemStatus.DONE
        original_work_item = {
            'title': 'The same work item',
            'status': original_status,
            'assignee': None,
            'milestone': None,
            'sequence': 0
        }
        new_work_item = {
            'title': 'The same work item',
            'status': new_status,
            'assignee': None,
            'milestone': None,
            'sequence': 0
        }
        login_person(spec.owner)
        spec.updateWorkItems([original_work_item])
        # In production this notification is fired by lazr.restful, but we
        # need to do it ourselves in this test.
        with notify_modified(spec, ['workitems_text']):
            stub.test_emails = []
            spec.updateWorkItems([new_work_item])
        transaction.commit()

        self.assertEqual(1, len(stub.test_emails))
        rationale_removed = '- %s: %s' % (original_work_item['title'],
                                          original_work_item['status'].name)
        rationale_added = '+ %s: %s' % (new_work_item['title'],
                                        new_work_item['status'].name)
        [email] = stub.test_emails
        # Actual message is part 2 of the email.
        msg = email[2]
        self.assertIn(rationale_removed, msg)
        self.assertIn(rationale_added, msg)
Пример #28
0
 def subscribe(self, person, subscribed_by=None, essential=False):
     """See ISpecification."""
     if subscribed_by is None:
         subscribed_by = person
     # Create or modify a user's subscription to this blueprint.
     # First see if a relevant subscription exists, and if so, return it
     sub = self.subscription(person)
     if sub is not None:
         if sub.essential != essential:
             # If a subscription already exists, but the value for
             # 'essential' changes, there's no need to create a new
             # subscription, but we modify the existing subscription
             # and notify the user about the change.
             with notify_modified(sub, ['essential'], user=subscribed_by):
                 sub.essential = essential
         return sub
     # since no previous subscription existed, create and return a new one
     sub = SpecificationSubscription(specification=self,
         person=person, essential=essential)
     property_cache = get_property_cache(self)
     if 'subscription' in property_cache:
         from lp.registry.model.person import person_sort_key
         property_cache.subscriptions.append(sub)
         property_cache.subscriptions.sort(
             key=lambda sub: person_sort_key(sub.person))
     if self.information_type in PRIVATE_INFORMATION_TYPES:
         # Grant the subscriber access if they can't see the
         # specification.
         service = getUtility(IService, 'sharing')
         _, _, _, shared_specs = service.getVisibleArtifacts(
             person, specifications=[self], ignore_permissions=True)
         if not shared_specs:
             service.ensureAccessGrants(
                 [person], subscribed_by, specifications=[self])
     notify(ObjectCreatedEvent(sub, user=subscribed_by))
     return sub
Пример #29
0
 def test_yields_previous_object(self):
     obj = Thing(0)
     with notify_modified(obj, []) as previous_obj:
         obj.attr = 1
         self.assertIsInstance(previous_obj, Snapshot)
         self.assertEqual(0, previous_obj.attr)