Ejemplo n.º 1
0
 def test_differing_profile_proj_shortname_rest_api(self):
     User.upsert('foo_bar')
     # default auth provider's user_project_shortname() converts _ to - (for subdomain name validation reasons)
     # but can access user URL with "_" still
     self.app.get('/rest/u/foo_bar/')
     # and with "-" too, no redirect here to avoid api clients having to deal with unexpected redirects
     self.app.get('/rest/u/foo-bar/')
Ejemplo n.º 2
0
 def test_link_to_send_message_form(self):
     User.by_username('test-admin').set_pref('email_address',
                                             '*****@*****.**')
     User.by_username('test-user').set_pref('email_address',
                                            '*****@*****.**')
     r = self.app.get('/u/test-user/profile', status=200)
     assert r.html.find('a', dict(href='send_message'))
Ejemplo n.º 3
0
 def test_link_to_send_message_form(self):
     User.by_username('test-admin').set_pref('email_address',
                                             '*****@*****.**')
     User.by_username('test-user').set_pref('email_address',
                                            '*****@*****.**')
     r = self.app.get('/u/test-user/profile',
                      status=200)
     assert r.html.find('a', dict(href='send_message'))
Ejemplo n.º 4
0
    def test_differing_profile_proj_shortname(self):
        User.upsert('foo_bar')

        # default auth provider's user_project_shortname() converts _ to - for the project name
        response = self.app.get('/u/foo_bar/', status=302)
        assert_equal(response.location, 'http://localhost/u/foo-bar/')
        response = self.app.get('/u/foo_bar/profile/xyz?a=b', status=302)
        assert_equal(response.location, 'http://localhost/u/foo-bar/profile/xyz?a=b')
Ejemplo n.º 5
0
    def test_differing_profile_proj_shortname(self):
        User.upsert('foo_bar')

        # default auth provider's user_project_shortname() converts _ to - for the project name
        response = self.app.get('/u/foo_bar/', status=302)
        assert_equal(response.location, 'http://localhost/u/foo-bar/')
        response = self.app.get('/u/foo_bar/profile/xyz?a=b', status=302)
        assert_equal(response.location, 'http://localhost/u/foo-bar/profile/xyz?a=b')
 def test_disable_user_messages(self):
     User.by_username('test-admin').set_pref('email_address', '*****@*****.**')
     test_user = User.by_username('test-user')
     test_user.set_pref('email_address', '*****@*****.**')
     test_user.set_pref('disable_user_messages', True)
     r = self.app.get('/u/test-user/profile')
     assert '<a href="send_message">Send me a message</a>' not in r
     r = self.app.get('/u/test-user/profile/send_message', status=302)
     assert 'This user has disabled direct email messages' in self.webflash(r)
Ejemplo n.º 7
0
    def test_user_messages_sender_disabled(self):
        admin_user = User.by_username('test-admin')
        admin_user.set_pref('email_address', '*****@*****.**')
        admin_user.set_pref('disable_user_messages', True)

        test_user = User.by_username('test-user')
        test_user.set_pref('email_address', '*****@*****.**')

        r = self.app.get('/u/test-user/profile/send_message', status=200)
        assert 'you currently have user messages disabled' in r
Ejemplo n.º 8
0
    def test_user_messages_sender_disabled(self):
        admin_user = User.by_username('test-admin')
        admin_user.set_pref('email_address', '*****@*****.**')
        admin_user.set_pref('disable_user_messages', True)

        test_user = User.by_username('test-user')
        test_user.set_pref('email_address', '*****@*****.**')

        r = self.app.get('/u/test-user/profile/send_message', status=200)
        assert 'you currently have user messages disabled' in r
Ejemplo n.º 9
0
 def test_disable_user_messages(self):
     User.by_username('test-admin').set_pref('email_address',
                                             '*****@*****.**')
     test_user = User.by_username('test-user')
     test_user.set_pref('email_address', '*****@*****.**')
     test_user.set_pref('disable_user_messages', True)
     r = self.app.get('/u/test-user/profile')
     assert '<a href="send_message">Send me a message</a>' not in r
     r = self.app.get('/u/test-user/profile/send_message', status=302)
     assert 'This user has disabled direct email messages' in self.webflash(
         r)
Ejemplo n.º 10
0
    def test_differing_profile_proj_shortname(self):
        User.upsert('foo_bar')
        # default auth provider's user_project_shortname() converts _ to - (for subdomain name validation reasons)
        # but can access user URL with "_" still
        self.app.get('/u/foo_bar/profile/')

        # and accessing it by "-" which was the previous way, will redirect
        response = self.app.get('/u/foo-bar/', status=302)
        assert_equal(response.location, 'http://localhost/u/foo_bar/')
        response = self.app.get('/u/foo-bar/profile/xyz?a=b', status=302)
        assert_equal(response.location, 'http://localhost/u/foo_bar/profile/xyz?a=b')
    def test_link_to_send_message_form(self):
        User.by_username('test-admin').set_pref('email_address', '*****@*****.**')
        User.by_username('test-user').set_pref('email_address', '*****@*****.**')
        r = self.app.get('/u/test-user/profile',
                         status=200)
        assert '<a href="send_message">Send me a message</a>' in r

        r = self.app.get('/u/test-user/profile',
                     extra_environ={'username': '******'},
                     status=200)

        assert '<a href="send_message">Send me a message</a>' not in r
Ejemplo n.º 12
0
    def test_ticket_move_with_users_not_in_project(self):
        app1 = c.project.app_instance('bugs')
        app2 = c.project.app_instance('bugs2')
        app1.globals.custom_fields.extend([
            {'name': '_user_field', 'type': 'user', 'label': 'User field'},
            {'name': '_user_field_2', 'type': 'user', 'label': 'User field 2'}])
        app2.globals.custom_fields.extend([
            {'name': '_user_field', 'type': 'user', 'label': 'User field'},
            {'name': '_user_field_2', 'type': 'user', 'label': 'User field 2'}])
        ThreadLocalORMSession.flush_all()
        ThreadLocalORMSession.close_all()
        from allura.websetup import bootstrap
        bootstrap.create_user('test-user-0')
        with h.push_context(c.project._id, app_config_id=app1.config._id):
            ticket = Ticket.new()
            ticket.summary = 'test ticket'
            ticket.description = 'test description'
            ticket.custom_fields['_user_field'] = 'test-user'  # in project
            # not in project
            ticket.custom_fields['_user_field_2'] = 'test-user-0'
            # not in project
            ticket.assigned_to_id = User.by_username('test-user-0')._id

        t = ticket.move(app2.config)
        assert_equal(t.assigned_to_id, None)
        assert_equal(t.custom_fields['_user_field'], 'test-user')
        assert_equal(t.custom_fields['_user_field_2'], '')
        post = Post.query.find(
            dict(thread_id=ticket.discussion_thread._id)).first()
        assert post is not None, 'No comment about ticket moving'
        message = 'Ticket moved from /p/test/bugs/1/'
        message += '\n\nCan\'t be converted:\n'
        message += '\n- **_user_field_2**: test-user-0 (user not in project)'
        message += '\n- **assigned_to**: test-user-0 (user not in project)'
        assert_equal(post.text, message)
Ejemplo n.º 13
0
    def setUp(self):
        from allura.model import User

        setup_basic_test()
        setup_global_objects()
        self.user = User.by_username("test-user-2")
        c.user = self.user
Ejemplo n.º 14
0
    def test_ticket_move(self):
        app1 = c.project.app_instance('bugs')
        app2 = c.project.app_instance('bugs2')
        with h.push_context(c.project._id, app_config_id=app1.config._id):
            ticket = Ticket.new()
            ticket.summary = 'test ticket'
            ticket.description = 'test description'
            ticket.assigned_to_id = User.by_username('test-user')._id
            ticket.discussion_thread.add_post(text='test comment')

        assert_equal(Ticket.query.find({'app_config_id': app1.config._id}).count(), 1)
        assert_equal(Ticket.query.find({'app_config_id': app2.config._id}).count(), 0)
        assert_equal(Post.query.find(dict(thread_id=ticket.discussion_thread._id)).count(), 1)

        t = ticket.move(app2.config)
        assert_equal(Ticket.query.find({'app_config_id': app1.config._id}).count(), 0)
        assert_equal(Ticket.query.find({'app_config_id': app2.config._id}).count(), 1)
        assert_equal(t.summary, 'test ticket')
        assert_equal(t.description, 'test description')
        assert_equal(t.assigned_to.username, 'test-user')
        assert_equal(t.url(), '/p/test/bugs2/1/')

        post = Post.query.find(dict(thread_id=ticket.discussion_thread._id,
                                    text={'$ne': 'test comment'})).first()
        assert post is not None, 'No comment about ticket moving'
        message = 'Ticket moved from /p/test/bugs/1/'
        assert_equal(post.text, message)

        post = Post.query.find(dict(text='test comment')).first()
        assert_equal(post.thread.discussion_id, app2.config.discussion_id)
        assert_equal(post.thread.app_config_id, app2.config._id)
        assert_equal(post.app_config_id, app2.config._id)
Ejemplo n.º 15
0
    def test_login(self):
        user = User.by_username("test-user")
        init_logins = user.stats.tot_logins_count
        r = self.app.post("/auth/do_login", params=dict(username=user.username, password="******"))

        assert user.stats.tot_logins_count == 1 + init_logins
        assert user.stats.getLastMonthLogins() == 1 + init_logins
Ejemplo n.º 16
0
 def _to_python(self, value, state):
     from allura.model import User
     if value:
         if c.user == User.anonymous():
             raise fe.Invalid('Log in to Mark as Private', value, state)
         else:
             return value
Ejemplo n.º 17
0
    def test_ticket_move_with_users_not_in_project(self):
        app1 = c.project.app_instance('bugs')
        app2 = c.project.app_instance('bugs2')
        app1.globals.custom_fields.extend([
            {'name': '_user_field', 'type': 'user', 'label': 'User field'},
            {'name': '_user_field_2', 'type': 'user', 'label': 'User field 2'}])
        app2.globals.custom_fields.extend([
            {'name': '_user_field', 'type': 'user', 'label': 'User field'},
            {'name': '_user_field_2', 'type': 'user', 'label': 'User field 2'}])
        ThreadLocalORMSession.flush_all()
        ThreadLocalORMSession.close_all()
        from allura.websetup import bootstrap
        bootstrap.create_user('test-user-0')
        with h.push_context(c.project._id, app_config_id=app1.config._id):
            ticket = Ticket.new()
            ticket.summary = 'test ticket'
            ticket.description = 'test description'
            ticket.custom_fields['_user_field'] = 'test-user'  # in project
            ticket.custom_fields['_user_field_2'] = 'test-user-0'  # not in project
            ticket.assigned_to_id = User.by_username('test-user-0')._id  # not in project

        t = ticket.move(app2.config)
        assert_equal(t.assigned_to_id, None)
        assert_equal(t.custom_fields['_user_field'], 'test-user')
        assert_equal(t.custom_fields['_user_field_2'], '')
        post = Post.query.find(dict(thread_id=ticket.discussion_thread._id)).first()
        assert post is not None, 'No comment about ticket moving'
        message = 'Ticket moved from /p/test/bugs/1/'
        message += '\n\nCan\'t be converted:\n'
        message += '\n- **_user_field_2**: test-user-0 (user not in project)'
        message += '\n- **assigned_to**: test-user-0 (user not in project)'
        assert_equal(post.text, message)
Ejemplo n.º 18
0
    def setUp(self):
        from allura.model import User

        setup_basic_test()
        setup_global_objects()
        self.user = User.by_username('test-user-2')
        c.user = self.user
Ejemplo n.º 19
0
    def move(self, app_config, notify=True):
        """Move ticket from current tickets app to tickets app with given app_config"""
        app = app_config.project.app_instance(app_config)
        prior_url = self.url()
        prior_app = self.app
        prior_ticket_num = self.ticket_num
        attachments = self.attachments
        attach_metadata = BaseAttachment.metadata_for(self)
        prior_cfs = [(cf["name"], cf["type"], cf["label"]) for cf in prior_app.globals.custom_fields or []]
        new_cfs = [(cf["name"], cf["type"], cf["label"]) for cf in app.globals.custom_fields or []]
        skipped_fields = []
        user_fields = []
        for cf in prior_cfs:
            if cf not in new_cfs:  # can't convert
                skipped_fields.append(cf)
            elif cf[1] == "user":  # can convert and field type == user
                user_fields.append(cf)
        messages = []
        for cf in skipped_fields:
            name = cf[0]
            messages.append("- **%s**: %s" % (name, self.custom_fields.get(name, "")))
        for cf in user_fields:
            name = cf[0]
            username = self.custom_fields.get(name, None)
            user = app_config.project.user_in_project(username)
            if not user or user == User.anonymous():
                messages.append("- **%s**: %s (user not in project)" % (name, username))
                self.custom_fields[name] = ""
        # special case: not custom user field (assigned_to_id)
        user = self.assigned_to
        if user and not app_config.project.user_in_project(user.username):
            messages.append("- **assigned_to**: %s (user not in project)" % user.username)
            self.assigned_to_id = None

        custom_fields = {}
        for cf in new_cfs:
            fn, ft, fl = cf
            old_val = self.custom_fields.get(fn, None)
            if old_val is None:
                custom_fields[fn] = None if ft == "user" else ""
            custom_fields[fn] = old_val
        self.custom_fields = custom_fields

        # move ticket. ensure unique ticket_num
        while True:
            with h.push_context(app_config.project_id, app_config_id=app_config._id):
                ticket_num = app.globals.next_ticket_num()
            self.ticket_num = ticket_num
            self.app_config_id = app_config._id
            new_url = app_config.url() + str(self.ticket_num) + "/"
            try:
                session(self).flush(self)
                h.log_action(log, "moved").info("Ticket %s moved to %s" % (prior_url, new_url))
                break
            except OperationFailure, err:
                if "duplicate" in err.args[0]:
                    log.warning("Try to create duplicate ticket %s when moving from %s" % (new_url, prior_url))
                    session(self).expunge(self)
                    continue
Ejemplo n.º 20
0
    def test_login(self):
        user = User.by_username('test-user')
        init_logins = c.user.stats.tot_logins_count
        r = self.app.post('/auth/do_login',
                          params=dict(username=user.username, password='******'))

        assert user.stats.tot_logins_count == 1 + init_logins
        assert user.stats.getLastMonthLogins() == 1 + init_logins
Ejemplo n.º 21
0
    def test_login(self):
        user = User.by_username('test-user')
        init_logins = user.stats.tot_logins_count
        self.app.post('/auth/do_login', params=dict(
            username=user.username, password='******'))

        assert user.stats.tot_logins_count == 1 + init_logins
        assert user.stats.getLastMonthLogins() == 1 + init_logins
Ejemplo n.º 22
0
 def update(self, ticket_form):
     self.globals.invalidate_bin_counts()
     # update is not allowed to change the ticket_num
     ticket_form.pop('ticket_num', None)
     self.labels = ticket_form.pop('labels', [])
     custom_sums = set()
     custom_users = set()
     other_custom_fields = set()
     for cf in self.globals.custom_fields or []:
         (custom_sums if cf['type'] == 'sum' else custom_users
          if cf['type'] == 'user' else other_custom_fields).add(cf['name'])
         if cf['type'] == 'boolean' and 'custom_fields.' + cf[
                 'name'] not in ticket_form:
             self.custom_fields[cf['name']] = 'False'
     # this has to happen because the milestone custom field has special layout treatment
     if '_milestone' in ticket_form:
         other_custom_fields.add('_milestone')
         milestone = ticket_form.pop('_milestone', None)
         if 'custom_fields' not in ticket_form:
             ticket_form['custom_fields'] = dict()
         ticket_form['custom_fields']['_milestone'] = milestone
     attachment = None
     if 'attachment' in ticket_form:
         attachment = ticket_form.pop('attachment')
     for k, v in ticket_form.iteritems():
         if k == 'assigned_to':
             if v:
                 user = c.project.user_in_project(v)
                 if user:
                     self.assigned_to_id = user._id
         elif k != 'super_id':
             setattr(self, k, v)
     if 'custom_fields' in ticket_form:
         for k, v in ticket_form['custom_fields'].iteritems():
             if k in custom_sums:
                 # sums must be coerced to numeric type
                 try:
                     self.custom_fields[k] = float(v)
                 except (TypeError, ValueError):
                     self.custom_fields[k] = 0
             elif k in custom_users:
                 # restrict custom user field values to project members
                 user = self.app_config.project.user_in_project(v)
                 self.custom_fields[k] = user.username \
                     if user and user != User.anonymous() else ''
             elif k in other_custom_fields:
                 # strings are good enough for any other custom fields
                 self.custom_fields[k] = v
     self.commit()
     if attachment is not None:
         self.attach(attachment.filename,
                     attachment.file,
                     content_type=attachment.type)
     # flush so we can participate in a subticket search (if any)
     session(self).flush()
     super_id = ticket_form.get('super_id')
     if super_id:
         self.set_as_subticket_of(bson.ObjectId(super_id))
Ejemplo n.º 23
0
    def test_private_ticket(self):
        from pylons import c
        from allura.model import ProjectRole, User
        from allura.model import ACE, ALL_PERMISSIONS, DENY_ALL
        from allura.lib.security import Credentials, has_access
        from allura.websetup import bootstrap

        admin = c.user
        creator = bootstrap.create_user('Not a Project Admin')
        developer = bootstrap.create_user('Project Developer')
        observer = bootstrap.create_user('Random Non-Project User')
        anon = User(_id=None, username='******', display_name='Anonymous')
        t = Ticket(summary='my ticket',
                   ticket_num=3,
                   reported_by_id=creator._id)

        assert creator == t.reported_by
        role_admin = ProjectRole.by_name('Admin')._id
        role_developer = ProjectRole.by_name('Developer')._id
        role_creator = t.reported_by.project_role()._id
        developer.project_role().roles.append(role_developer)
        cred = Credentials.get().clear()

        t.private = True
        assert t.acl == [
            ACE.allow(role_developer, ALL_PERMISSIONS),
            ACE.allow(role_creator, ALL_PERMISSIONS), DENY_ALL
        ]
        assert has_access(t, 'read', user=admin)()
        assert has_access(t, 'create', user=admin)()
        assert has_access(t, 'update', user=admin)()
        assert has_access(t, 'read', user=creator)()
        assert has_access(t, 'create', user=creator)()
        assert has_access(t, 'update', user=creator)()
        assert has_access(t, 'read', user=developer)()
        assert has_access(t, 'create', user=developer)()
        assert has_access(t, 'update', user=developer)()
        assert not has_access(t, 'read', user=observer)()
        assert not has_access(t, 'create', user=observer)()
        assert not has_access(t, 'update', user=observer)()
        assert not has_access(t, 'read', user=anon)()
        assert not has_access(t, 'create', user=anon)()
        assert not has_access(t, 'update', user=anon)()

        t.private = False
        assert t.acl == []
        assert has_access(t, 'read', user=admin)()
        assert has_access(t, 'create', user=admin)()
        assert has_access(t, 'update', user=admin)()
        assert has_access(t, 'read', user=developer)()
        assert has_access(t, 'create', user=developer)()
        assert has_access(t, 'update', user=developer)()
        assert has_access(t, 'read', user=creator)()
        assert has_access(t, 'unmoderated_post', user=creator)()
        assert not has_access(t, 'create', user=creator)()
        assert not has_access(t, 'update', user=creator)()
        assert has_access(t, 'read', user=observer)()
        assert has_access(t, 'read', user=anon)()
Ejemplo n.º 24
0
    def setUp(self):
        super(TestGitCommit, self).setUp()
        setup_basic_test()

        user = User.by_username('test-admin')
        user.set_password('testpassword')
        addr = M.EmailAddress.upsert('*****@*****.**')
        user.claim_address('*****@*****.**')
        self.setup_with_tools()
Ejemplo n.º 25
0
    def setUp(self):
        super(TestGitCommit, self).setUp()
        setup_basic_test()

        user = User.by_username('test-admin')
        user.set_password('testpassword')
        addr = M.EmailAddress.upsert('*****@*****.**')
        user.claim_address('*****@*****.**')
        self.setup_with_tools()
Ejemplo n.º 26
0
    def test_login(self):
        user = User.by_username('test-user')
        init_logins = user.stats.tot_logins_count
        self.app.get('/').follow()  # establish session
        self.app.post('/auth/do_login', antispam=True, params=dict(
            username=user.username, password='******',
            _session_id=self.app.cookies['_session_id'],
        ))

        assert user.stats.tot_logins_count == 1 + init_logins
        assert user.stats.getLastMonthLogins() == 1 + init_logins
Ejemplo n.º 27
0
    def test_login(self):
        user = User.by_username('test-user')
        init_logins = user.stats.tot_logins_count
        self.app.get('/')  # establish session
        self.app.post('/auth/do_login', params=dict(
            username=user.username, password='******',
            _session_id=self.app.cookies['_session_id']
        ))

        assert user.stats.tot_logins_count == 1 + init_logins
        assert user.stats.getLastMonthLogins() == 1 + init_logins
Ejemplo n.º 28
0
    def test_send_message(self, check, gen_message_id, sendsimplemail):
        check.return_value = True
        gen_message_id.return_value = 'id'
        test_user = User.by_username('test-user')
        test_user.set_pref('email_address', '*****@*****.**')
        response = self.app.get('/u/test-user/profile/send_message',
                                status=200)
        assert 'you currently have user messages disabled' not in response
        response.mustcontain(
            '<b>From:</b> &#34;Test Admin&#34; &lt;[email protected]&gt;'
        )

        self.app.post('/u/test-user/profile/send_user_message',
                      params={
                          'subject': 'test subject',
                          'message': 'test message',
                          'cc': 'on'
                      })

        sendsimplemail.post.assert_called_once_with(
            cc=User.by_username('test-admin').get_pref('email_address'),
            text=
            'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
            toaddr=User.by_username('test-user').get_pref('email_address'),
            fromaddr=User.by_username('test-admin').get_pref('email_address'),
            reply_to=User.by_username('test-admin').get_pref('email_address'),
            message_id='id',
            subject='test subject')
        sendsimplemail.reset_mock()
        self.app.post('/u/test-user/profile/send_user_message',
                      params={
                          'subject': 'test subject',
                          'message': 'test message'
                      })

        sendsimplemail.post.assert_called_once_with(
            cc=None,
            text=
            'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
            toaddr=User.by_username('test-user').get_pref('email_address'),
            fromaddr=User.by_username('test-admin').get_pref('email_address'),
            reply_to=User.by_username('test-admin').get_pref('email_address'),
            message_id='id',
            subject='test subject')

        check.return_value = False
        response = self.app.get('/u/test-user/profile/send_message',
                                status=200)
        assert 'Sorry, messaging is rate-limited' in response
Ejemplo n.º 29
0
    def test_profile_user_card(self):
        user = User.by_username('test-admin')
        locals =  {
            'city': 'test-city',
            'country': 'US'
        }
        webpages = ['http://allura.apache.org/']
        user.set_pref('localization', locals)
        user.set_pref('webpages', webpages)
        r = self.app.get('/u/test-admin/profile/user_card')

        assert user.icon_url() in r.html.find('img').attrs['src']
        assert user.display_name == r.html.find('div', attrs={'class': 'name'}).getText()
        assert user.get_pref('localization')['city'] in r.html.find('span', attrs={'class': 'subitem-loc'}).getText()
        assert user.get_pref('localization')['country'] in r.html.find('span', attrs={'class': 'subitem-loc'}).getText()
        assert user.get_pref('webpages')[0] in str(r.html.find('span', attrs={'class': 'subitem-web'}))
Ejemplo n.º 30
0
    def test_ticket_move(self):
        app1 = c.project.app_instance('bugs')
        app2 = c.project.app_instance('bugs2')
        with h.push_context(c.project._id, app_config_id=app1.config._id):
            ticket = Ticket.new()
            ticket.summary = 'test ticket'
            ticket.description = 'test description'
            ticket.assigned_to_id = User.by_username('test-user')._id
            ticket.discussion_thread.add_post(text='test comment')

        assert_equal(
            Ticket.query.find({
                'app_config_id': app1.config._id
            }).count(), 1)
        assert_equal(
            Ticket.query.find({
                'app_config_id': app2.config._id
            }).count(), 0)
        assert_equal(
            Post.query.find(
                dict(thread_id=ticket.discussion_thread._id)).count(), 1)

        t = ticket.move(app2.config)
        assert_equal(
            Ticket.query.find({
                'app_config_id': app1.config._id
            }).count(), 0)
        assert_equal(
            Ticket.query.find({
                'app_config_id': app2.config._id
            }).count(), 1)
        assert_equal(t.summary, 'test ticket')
        assert_equal(t.description, 'test description')
        assert_equal(t.assigned_to.username, 'test-user')
        assert_equal(t.url(), '/p/test/bugs2/1/')

        post = Post.query.find(
            dict(thread_id=ticket.discussion_thread._id,
                 text={'$ne': 'test comment'})).first()
        assert post is not None, 'No comment about ticket moving'
        message = 'Ticket moved from /p/test/bugs/1/'
        assert_equal(post.text, message)

        post = Post.query.find(dict(text='test comment')).first()
        assert_equal(post.thread.discussion_id, app2.config.discussion_id)
        assert_equal(post.thread.app_config_id, app2.config._id)
        assert_equal(post.app_config_id, app2.config._id)
Ejemplo n.º 31
0
 def update(self, ticket_form):
     self.globals.invalidate_bin_counts()
     # update is not allowed to change the ticket_num
     ticket_form.pop('ticket_num', None)
     self.labels = ticket_form.pop('labels', [])
     custom_users = set()
     other_custom_fields = set()
     for cf in self.globals.custom_fields or []:
         (custom_users
          if cf['type'] == 'user' else other_custom_fields).add(cf['name'])
         if cf['type'] == 'boolean' and 'custom_fields.' + cf[
                 'name'] not in ticket_form:
             self.custom_fields[cf['name']] = 'False'
     # this has to happen because the milestone custom field has special layout treatment
     if '_milestone' in ticket_form:
         other_custom_fields.add('_milestone')
         milestone = ticket_form.pop('_milestone', None)
         if 'custom_fields' not in ticket_form:
             ticket_form['custom_fields'] = dict()
         ticket_form['custom_fields']['_milestone'] = milestone
     attachment = None
     if 'attachment' in ticket_form:
         attachment = ticket_form.pop('attachment')
     for k, v in ticket_form.iteritems():
         if k == 'assigned_to':
             if v:
                 user = c.project.user_in_project(v)
                 if user:
                     self.assigned_to_id = user._id
         else:
             setattr(self, k, v)
     if 'custom_fields' in ticket_form:
         for k, v in ticket_form['custom_fields'].iteritems():
             if k in custom_users:
                 # restrict custom user field values to project members
                 user = self.app_config.project.user_in_project(v)
                 self.custom_fields[k] = user.username \
                     if user and user != User.anonymous() else ''
             elif k in other_custom_fields:
                 # strings are good enough for any other custom fields
                 self.custom_fields[k] = v
     self.commit()
     if attachment is not None:
         self.attach(attachment.filename,
                     attachment.file,
                     content_type=attachment.type)
Ejemplo n.º 32
0
 def update(self, ticket_form):
     self.globals.invalidate_bin_counts()
     # update is not allowed to change the ticket_num
     ticket_form.pop('ticket_num', None)
     self.labels = ticket_form.pop('labels', [])
     custom_users = set()
     other_custom_fields = set()
     for cf in self.globals.custom_fields or []:
         (custom_users if cf['type'] == 'user' else
          other_custom_fields).add(cf['name'])
         if cf['type'] == 'boolean' and 'custom_fields.' + cf['name'] not in ticket_form:
             self.custom_fields[cf['name']] = 'False'
     # this has to happen because the milestone custom field has special layout treatment
     if '_milestone' in ticket_form:
         other_custom_fields.add('_milestone')
         milestone = ticket_form.pop('_milestone', None)
         if 'custom_fields' not in ticket_form:
             ticket_form['custom_fields'] = dict()
         ticket_form['custom_fields']['_milestone'] = milestone
     attachment = None
     if 'attachment' in ticket_form:
         attachment = ticket_form.pop('attachment')
     for k, v in ticket_form.iteritems():
         if k == 'assigned_to':
             if v:
                 user = c.project.user_in_project(v)
                 if user:
                     self.assigned_to_id = user._id
         else:
             setattr(self, k, v)
     if 'custom_fields' in ticket_form:
         for k,v in ticket_form['custom_fields'].iteritems():
             if k in custom_users:
                 # restrict custom user field values to project members
                 user = self.app_config.project.user_in_project(v)
                 self.custom_fields[k] = user.username \
                     if user and user != User.anonymous() else ''
             elif k in other_custom_fields:
                 # strings are good enough for any other custom fields
                 self.custom_fields[k] = v
     self.commit()
     if attachment is not None:
         self.attach(
             attachment.filename, attachment.file,
             content_type=attachment.type)
Ejemplo n.º 33
0
 def feed(self, since=None, until=None, page=None, limit=None):
     username = c.project.shortname.split('/')[1]
     user = User.by_username(username)
     if request.environ['PATH_INFO'].endswith('.atom'):
         feed_type = 'atom'
     else:
         feed_type = 'rss'
     title = 'Recent posts by %s' % user.display_name
     feed = Notification.feed(
         {'author_id':user._id},
         feed_type,
         title,
         c.project.url(),
         title,
         since, until, page, limit)
     response.headers['Content-Type'] = ''
     response.content_type = 'application/xml'
     return feed.writeString('utf-8')
Ejemplo n.º 34
0
    def _check_can_message(self, from_user, to_user):
        if from_user is User.anonymous():
            flash('You must be logged in to send user messages.', 'info')
            redirect(request.referer or '/')

        if not (from_user and from_user.get_pref('email_address')):
            flash('In order to send messages, you must have an email address '
                  'associated with your account.', 'info')
            redirect(request.referer or '/')

        if not (to_user and to_user.get_pref('email_address')):
            flash('This user can not receive messages because they do not have '
                  'an email address associated with their account.', 'info')
            redirect(request.referer or '/')

        if to_user.get_pref('disable_user_messages'):
            flash('This user has disabled direct email messages', 'info')
            redirect(request.referer or '/')
Ejemplo n.º 35
0
 def get_custom_user(self, custom_user_field_name):
     fld = None
     for f in c.app.globals.custom_fields:
         if f.name == custom_user_field_name:
             fld = f
             break
     if not fld:
         raise KeyError, 'Custom field "%s" does not exist.' % custom_user_field_name
     if fld.type != 'user':
         raise TypeError, 'Custom field "%s" is of type "%s"; expected ' \
                          'type "user".' % (custom_user_field_name, fld.type)
     username = self.custom_fields.get(custom_user_field_name)
     if not username:
         return None
     user = self.app_config.project.user_in_project(username)
     if user == User.anonymous():
         return None
     return user
Ejemplo n.º 36
0
 def get_custom_user(self, custom_user_field_name):
     fld = None
     for f in c.app.globals.custom_fields:
         if f.name == custom_user_field_name:
             fld = f
             break
     if not fld:
         raise KeyError, 'Custom field "%s" does not exist.' % custom_user_field_name
     if fld.type != 'user':
         raise TypeError, 'Custom field "%s" is of type "%s"; expected ' \
                          'type "user".' % (custom_user_field_name, fld.type)
     username = self.custom_fields.get(custom_user_field_name)
     if not username:
         return None
     user = self.app_config.project.user_in_project(username)
     if user == User.anonymous():
         return None
     return user
Ejemplo n.º 37
0
    def _check_can_message(self, from_user, to_user):
        if from_user is User.anonymous():
            flash('You must be logged in to send user messages.', 'info')
            redirect(request.referer)

        if not (from_user and from_user.get_pref('email_address')):
            flash('In order to send messages, you must have an email address '
                  'associated with your account.', 'info')
            redirect(request.referer)

        if not (to_user and to_user.get_pref('email_address')):
            flash('This user can not receive messages because they do not have '
                  'an email address associated with their account.', 'info')
            redirect(request.referer)

        if to_user.get_pref('disable_user_messages'):
            flash('This user has disabled direct email messages', 'info')
            redirect(request.referer)
Ejemplo n.º 38
0
 def update(self, ticket_form):
     # update is not allowed to change the ticket_num
     ticket_form.pop("ticket_num", None)
     self.labels = ticket_form.pop("labels", [])
     custom_users = set()
     other_custom_fields = set()
     for cf in self.globals.custom_fields or []:
         (custom_users if cf["type"] == "user" else other_custom_fields).add(cf["name"])
         if cf["type"] == "boolean" and "custom_fields." + cf["name"] not in ticket_form:
             self.custom_fields[cf["name"]] = "False"
     # this has to happen because the milestone custom field has special
     # layout treatment
     if "_milestone" in ticket_form:
         other_custom_fields.add("_milestone")
         milestone = ticket_form.pop("_milestone", None)
         if "custom_fields" not in ticket_form:
             ticket_form["custom_fields"] = dict()
         ticket_form["custom_fields"]["_milestone"] = milestone
     attachment = None
     if "attachment" in ticket_form:
         attachment = ticket_form.pop("attachment")
     for k, v in ticket_form.iteritems():
         if k == "assigned_to":
             if v:
                 user = c.project.user_in_project(v)
                 if user:
                     self.assigned_to_id = user._id
         else:
             setattr(self, k, v)
     if "custom_fields" in ticket_form:
         for k, v in ticket_form["custom_fields"].iteritems():
             if k in custom_users:
                 # restrict custom user field values to project members
                 user = self.app_config.project.user_in_project(v)
                 self.custom_fields[k] = user.username if user and user != User.anonymous() else ""
             elif k in other_custom_fields:
                 # strings are good enough for any other custom fields
                 self.custom_fields[k] = v
     if attachment is not None:
         self.add_multiple_attachments(attachment)
         # flush the session to make attachments available in the
         # notification email
         ThreadLocalORMSession.flush_all()
     self.commit()
Ejemplo n.º 39
0
    def test_send_message(self, check, gen_message_id, sendsimplemail):
        check.return_value = True
        gen_message_id.return_value = 'id'
        test_user = User.by_username('test-user')
        test_user.set_pref('email_address', '*****@*****.**')
        response = self.app.get(
            '/u/test-user/profile/send_message', status=200)
        assert 'you currently have user messages disabled' not in response
        assert '<b>From:</b> &#34;Test Admin&#34; &lt;[email protected]&gt;' in response

        self.app.post('/u/test-user/profile/send_user_message',
                      params={'subject': 'test subject',
                              'message': 'test message',
                              'cc': 'on'})

        sendsimplemail.post.assert_called_once_with(
            cc=User.by_username('test-admin').get_pref('email_address'),
            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
            toaddr=User.by_username('test-user').get_pref('email_address'),
            fromaddr=User.by_username('test-admin').get_pref('email_address'),
            reply_to=User.by_username('test-admin').get_pref('email_address'),
            message_id=u'id',
            subject=u'test subject')
        sendsimplemail.reset_mock()
        self.app.post('/u/test-user/profile/send_user_message',
                      params={'subject': 'test subject',
                              'message': 'test message'})

        sendsimplemail.post.assert_called_once_with(
            cc=None,
            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
            toaddr=User.by_username('test-user').get_pref('email_address'),
            fromaddr=User.by_username('test-admin').get_pref('email_address'),
            reply_to=User.by_username('test-admin').get_pref('email_address'),
            message_id=u'id',
            subject=u'test subject')

        check.return_value = False
        response = self.app.get(
            '/u/test-user/profile/send_message', status=200)
        assert 'Sorry, messaging is rate-limited' in response
Ejemplo n.º 40
0
 def setUp(self):
     setup_basic_test()
     setup_global_objects()
     self.user = User.by_username('test-user-2')
     c.user = self.user
Ejemplo n.º 41
0
    def update_tickets(self, **post_data):
        from forgetracker.tracker_main import get_change_text, get_label
        tickets = Ticket.query.find(dict(
                _id={'$in':[ObjectId(id) for id in aslist(post_data['__ticket_ids'])]},
                app_config_id=self.app_config_id)).all()

        fields = set(['status', 'private'])
        values = {}
        labels = post_data.get('labels', [])

        for k in fields:
            v = post_data.get(k)
            if v: values[k] = v
        assigned_to = post_data.get('assigned_to')
        if assigned_to == '-':
            values['assigned_to_id'] = None
        elif assigned_to:
            user = c.project.user_in_project(assigned_to)
            if user:
                values['assigned_to_id'] = user._id
        private = post_data.get('private')
        if private:
            values['private'] = asbool(private)

        custom_values = {}
        custom_fields = {}
        for cf in self.custom_fields or []:
            v = post_data.get(cf.name)
            if v:
                custom_values[cf.name] = v
                custom_fields[cf.name] = cf

        changes = {}
        changed_tickets = {}
        for ticket in tickets:
            message = ''
            if labels:
                values['labels'] = self.append_new_labels(ticket.labels, labels.split(','))
            for k, v in sorted(values.iteritems()):
                if k == 'assigned_to_id':
                    new_user = User.query.get(_id=v)
                    old_user = User.query.get(_id=getattr(ticket, k))
                    if new_user:
                        message += get_change_text(
                            get_label(k),
                            new_user.display_name,
                            old_user.display_name)
                elif k == 'private':
                    def private_text(val):
                        if val:
                            return 'Yes'
                        else:
                            return 'No'
                    message += get_change_text(
                        get_label(k),
                        private_text(v),
                        private_text(getattr(ticket, k)))
                else:
                    message += get_change_text(
                        get_label(k),
                        v,
                        getattr(ticket, k))
                setattr(ticket, k, v)
            for k, v in sorted(custom_values.iteritems()):
                def cf_val(cf):
                    return ticket.get_custom_user(cf.name) \
                           if cf.type == 'user' \
                           else ticket.custom_fields.get(cf.name)
                cf = custom_fields[k]
                old_value = cf_val(cf)
                if cf.type == 'boolean':
                    v = asbool(v)
                ticket.custom_fields[k] = v
                new_value = cf_val(cf)
                message += get_change_text(
                    cf.label,
                    new_value,
                    old_value)
            if message != '':
                changes[ticket._id] = message
                changed_tickets[ticket._id] = ticket
                ticket.discussion_thread.post(message, notify=False)
                ticket.commit()

        filtered_changes = self.filtered_by_subscription(changed_tickets)
        users = User.query.find({'_id': {'$in': filtered_changes.keys()}}).all()
        def changes_iter(user):
            for t_id in filtered_changes.get(user._id, []):
                # mark changes text as safe, thus it wouldn't be escaped in plain-text emails
                # html part of email is handled by markdown and it'll be properly escaped
                yield (changed_tickets[t_id], jinja2.Markup(changes[t_id]))
        mail = dict(
            sender = c.project.app_instance(self.app_config).email_address,
            fromaddr = str(c.user._id),
            reply_to = tg_config['forgemail.return_path'],
            subject = '[%s:%s] Mass edit changes by %s' % (c.project.shortname,
                                                           self.app_config.options.mount_point,
                                                           c.user.display_name),
        )
        tmpl = g.jinja2_env.get_template('forgetracker:data/mass_report.html')
        head = []
        for f, v in sorted(values.iteritems()):
            if f == 'assigned_to_id':
                user = User.query.get(_id=v)
                v = user.display_name if user else v
            head.append('- **%s**: %s' % (get_label(f), v))
        for f, v in sorted(custom_values.iteritems()):
            cf = custom_fields[f]
            if cf.type == 'user':
                user = User.by_username(v)
                v = user.display_name if user else v
            head.append('- **%s**: %s' % (cf.label, v))
        tmpl_context = {'context': c, 'data': {'header': jinja2.Markup('\n'.join(['Mass edit changing:', ''] + head))}}
        for user in users:
            tmpl_context['data'].update({'changes': changes_iter(user)})
            mail.update(dict(
                message_id = h.gen_message_id(),
                text = tmpl.render(tmpl_context),
                destinations = [str(user._id)]))
            mail_tasks.sendmail.post(**mail)

        if self.app_config.options.get('TicketMonitoringType') in (
                'AllTicketChanges', 'AllPublicTicketChanges'):
            monitoring_email = self.app_config.options.get('TicketMonitoringEmail')
            visible_changes = []
            for t_id, t in changed_tickets.items():
                if (not t.private or
                        self.app_config.options.get('TicketMonitoringType') ==
                        'AllTicketChanges'):
                    visible_changes.append(
                            (changed_tickets[t_id], jinja2.Markup(changes[t_id])))
            if visible_changes:
                tmpl_context['data'].update({'changes': visible_changes})
                mail.update(dict(
                    message_id = h.gen_message_id(),
                    text = tmpl.render(tmpl_context),
                    destinations = [monitoring_email]))
                mail_tasks.sendmail.post(**mail)

        self.invalidate_bin_counts()
        ThreadLocalORMSession.flush_all()
        app = '%s/%s' % (c.project.shortname, self.app_config.options.mount_point)
        count = len(tickets)
        text = 'Updated {} ticket{} in {}'.format(count, 's' if count != 1 else '', app)
        Notification.post_user(c.user, None, 'flash', text=text)
Ejemplo n.º 42
0
 def assigned_to_name(self):
     who = self.assigned_to
     if who in (None, User.anonymous()): return 'nobody'
     return who.get_pref('display_name')
Ejemplo n.º 43
0
 def assigned_to_name(self):
     who = self.assigned_to
     if who in (None, User.anonymous()): return 'nobody'
     return who.get_pref('display_name')
Ejemplo n.º 44
0
 def setUp(self):
     super(WithUserAndBugsApp, self).setUp()
     c.user = User(username='******')
     h.set_context('test', 'bugs', neighborhood='Projects')
Ejemplo n.º 45
0
    def update_tickets(self, **post_data):
        from forgetracker.tracker_main import get_change_text, get_label
        tickets = Ticket.query.find(
            dict(_id={
                '$in':
                [ObjectId(id) for id in aslist(post_data['__ticket_ids'])]
            },
                 app_config_id=self.app_config_id)).all()

        fields = set(['status', 'private'])
        values = {}
        labels = post_data.get('labels', [])

        for k in fields:
            v = post_data.get(k)
            if v: values[k] = v
        assigned_to = post_data.get('assigned_to')
        if assigned_to == '-':
            values['assigned_to_id'] = None
        elif assigned_to:
            user = c.project.user_in_project(assigned_to)
            if user:
                values['assigned_to_id'] = user._id
        private = post_data.get('private')
        if private:
            values['private'] = asbool(private)

        custom_values = {}
        custom_fields = {}
        for cf in self.custom_fields or []:
            v = post_data.get(cf.name)
            if v:
                custom_values[cf.name] = v
                custom_fields[cf.name] = cf

        changes = {}
        changed_tickets = {}
        for ticket in tickets:
            message = ''
            if labels:
                values['labels'] = self.append_new_labels(
                    ticket.labels, labels.split(','))
            for k, v in sorted(values.iteritems()):
                if k == 'assigned_to_id':
                    new_user = User.query.get(_id=v)
                    old_user = User.query.get(_id=getattr(ticket, k))
                    if new_user:
                        message += get_change_text(get_label(k),
                                                   new_user.display_name,
                                                   old_user.display_name)
                elif k == 'private':

                    def private_text(val):
                        if val:
                            return 'Yes'
                        else:
                            return 'No'

                    message += get_change_text(
                        get_label(k), private_text(v),
                        private_text(getattr(ticket, k)))
                else:
                    message += get_change_text(get_label(k), v,
                                               getattr(ticket, k))
                setattr(ticket, k, v)
            for k, v in sorted(custom_values.iteritems()):

                def cf_val(cf):
                    return ticket.get_custom_user(cf.name) \
                           if cf.type == 'user' \
                           else ticket.custom_fields.get(cf.name)

                cf = custom_fields[k]
                old_value = cf_val(cf)
                if cf.type == 'boolean':
                    v = asbool(v)
                ticket.custom_fields[k] = v
                new_value = cf_val(cf)
                message += get_change_text(cf.label, new_value, old_value)
            if message != '':
                changes[ticket._id] = message
                changed_tickets[ticket._id] = ticket
                ticket.discussion_thread.post(message, notify=False)
                ticket.commit()

        filtered_changes = self.filtered_by_subscription(changed_tickets)
        users = User.query.find({
            '_id': {
                '$in': filtered_changes.keys()
            }
        }).all()

        def changes_iter(user):
            for t_id in filtered_changes.get(user._id, []):
                # mark changes text as safe, thus it wouldn't be escaped in plain-text emails
                # html part of email is handled by markdown and it'll be properly escaped
                yield (changed_tickets[t_id], jinja2.Markup(changes[t_id]))

        mail = dict(
            sender=c.project.app_instance(self.app_config).email_address,
            fromaddr=str(c.user._id),
            reply_to=str(c.user._id),
            subject='[%s:%s] Mass edit changes by %s' %
            (c.project.shortname, self.app_config.options.mount_point,
             c.user.display_name),
        )
        tmpl = g.jinja2_env.get_template('forgetracker:data/mass_report.html')
        head = []
        for f, v in sorted(values.iteritems()):
            if f == 'assigned_to_id':
                user = User.query.get(_id=v)
                v = user.display_name if user else v
            head.append('- **%s**: %s' % (get_label(f), v))
        for f, v in sorted(custom_values.iteritems()):
            cf = custom_fields[f]
            if cf.type == 'user':
                user = User.by_username(v)
                v = user.display_name if user else v
            head.append('- **%s**: %s' % (cf.label, v))
        tmpl_context = {
            'context': c,
            'data': {
                'header':
                jinja2.Markup('\n'.join(['Mass edit changing:', ''] + head))
            }
        }
        for user in users:
            tmpl_context['data'].update({'changes': changes_iter(user)})
            mail.update(
                dict(message_id=h.gen_message_id(),
                     text=tmpl.render(tmpl_context),
                     destinations=[str(user._id)]))
            mail_tasks.sendmail.post(**mail)

        if self.app_config.options.get('TicketMonitoringType') in (
                'AllTicketChanges', 'AllPublicTicketChanges'):
            monitoring_email = self.app_config.options.get(
                'TicketMonitoringEmail')
            visible_changes = []
            for t_id, t in changed_tickets.items():
                if (not t.private
                        or self.app_config.options.get('TicketMonitoringType')
                        == 'AllTicketChanges'):
                    visible_changes.append(
                        (changed_tickets[t_id], jinja2.Markup(changes[t_id])))
            if visible_changes:
                tmpl_context['data'].update({'changes': visible_changes})
                mail.update(
                    dict(message_id=h.gen_message_id(),
                         text=tmpl.render(tmpl_context),
                         destinations=[monitoring_email]))
                mail_tasks.sendmail.post(**mail)

        self.invalidate_bin_counts()
        ThreadLocalORMSession.flush_all()
        app = '%s/%s' % (c.project.shortname,
                         self.app_config.options.mount_point)
        count = len(tickets)
        text = 'Updated {} ticket{} in {}'.format(count,
                                                  's' if count != 1 else '',
                                                  app)
        Notification.post_user(c.user, None, 'flash', text=text)
Ejemplo n.º 46
0
 def setUp(self):
     setup_basic_test()
     setup_global_objects()
     self.user = User.by_username('test-user-2')
     c.user = self.user
Ejemplo n.º 47
0
 def configuration(self):
     username = c.project.shortname.split('/')[1]
     user = User.by_username(username)
     return dict(user=user)
Ejemplo n.º 48
0
 def index(self, **kw):
     username = c.project.shortname.split('/')[1]
     user = User.by_username(username)
     return dict(user=user)
Ejemplo n.º 49
0
    def move(self, app_config, notify=True):
        '''Move ticket from current tickets app to tickets app with given app_config'''
        app = app_config.project.app_instance(app_config)
        prior_url = self.url()
        prior_app = self.app
        prior_ticket_num = self.ticket_num
        attachments = self.attachments
        attach_metadata = BaseAttachment.metadata_for(self)
        prior_cfs = [(cf['name'], cf['type'], cf['label'])
                     for cf in prior_app.globals.custom_fields or []]
        new_cfs = [(cf['name'], cf['type'], cf['label'])
                   for cf in app.globals.custom_fields or []]
        skipped_fields = []
        user_fields = []
        for cf in prior_cfs:
            if cf not in new_cfs:  # can't convert
                skipped_fields.append(cf)
            elif cf[1] == 'user':  # can convert and field type == user
                user_fields.append(cf)
        messages = []
        for cf in skipped_fields:
            name = cf[0]
            messages.append('- **%s**: %s' %
                            (name, self.custom_fields.get(name, '')))
        for cf in user_fields:
            name = cf[0]
            username = self.custom_fields.get(name, None)
            user = app_config.project.user_in_project(username)
            if not user or user == User.anonymous():
                messages.append('- **%s**: %s (user not in project)' %
                                (name, username))
                self.custom_fields[name] = ''
        # special case: not custom user field (assigned_to_id)
        user = self.assigned_to
        if user and not app_config.project.user_in_project(user.username):
            messages.append('- **assigned_to**: %s (user not in project)' %
                            user.username)
            self.assigned_to_id = None

        custom_fields = {}
        for cf in new_cfs:
            fn, ft, fl = cf
            old_val = self.custom_fields.get(fn, None)
            if old_val is None:
                custom_fields[fn] = None if ft == 'user' else ''
            custom_fields[fn] = old_val
        self.custom_fields = custom_fields

        # move ticket. ensure unique ticket_num
        while True:
            with h.push_context(app_config.project_id,
                                app_config_id=app_config._id):
                ticket_num = app.globals.next_ticket_num()
            self.ticket_num = ticket_num
            self.app_config_id = app_config._id
            new_url = app_config.url() + str(self.ticket_num) + '/'
            try:
                session(self).flush(self)
                h.log_action(log, 'moved').info('Ticket %s moved to %s' %
                                                (prior_url, new_url))
                break
            except OperationFailure, err:
                if 'duplicate' in err.args[0]:
                    log.warning(
                        'Try to create duplicate ticket %s when moving from %s'
                        % (new_url, prior_url))
                    session(self).expunge(self)
                    continue
Ejemplo n.º 50
0
    def test_private_ticket(self):
        from allura.model import ProjectRole
        from allura.model import ACE, DENY_ALL
        from allura.lib.security import Credentials, has_access
        from allura.websetup import bootstrap

        admin = c.user
        creator = bootstrap.create_user('Not a Project Admin')
        developer = bootstrap.create_user('Project Developer')
        observer = bootstrap.create_user('Random Non-Project User')
        anon = User(_id=None, username='******',
                    display_name='Anonymous')
        t = Ticket(summary='my ticket', ticket_num=3,
                   reported_by_id=creator._id)

        assert creator == t.reported_by
        role_admin = ProjectRole.by_name('Admin')._id
        role_developer = ProjectRole.by_name('Developer')._id
        role_creator = ProjectRole.by_user(t.reported_by, upsert=True)._id
        ProjectRole.by_user(
            developer, upsert=True).roles.append(role_developer)
        ThreadLocalORMSession.flush_all()
        cred = Credentials.get().clear()

        t.private = True
        assert_equal(t.acl, [
            ACE.allow(role_developer, 'save_searches'),
            ACE.allow(role_developer, 'read'),
            ACE.allow(role_developer, 'create'),
            ACE.allow(role_developer, 'update'),
            ACE.allow(role_developer, 'unmoderated_post'),
            ACE.allow(role_developer, 'post'),
            ACE.allow(role_developer, 'moderate'),
            ACE.allow(role_developer, 'delete'),
            ACE.allow(role_creator, 'read'),
            ACE.allow(role_creator, 'post'),
            ACE.allow(role_creator, 'create'),
            ACE.allow(role_creator, 'unmoderated_post'),
            DENY_ALL])
        assert has_access(t, 'read', user=admin)()
        assert has_access(t, 'create', user=admin)()
        assert has_access(t, 'update', user=admin)()
        assert has_access(t, 'read', user=creator)()
        assert has_access(t, 'post', user=creator)()
        assert has_access(t, 'unmoderated_post', user=creator)()
        assert has_access(t, 'create', user=creator)()
        assert not has_access(t, 'update', user=creator)()
        assert has_access(t, 'read', user=developer)()
        assert has_access(t, 'create', user=developer)()
        assert has_access(t, 'update', user=developer)()
        assert not has_access(t, 'read', user=observer)()
        assert not has_access(t, 'create', user=observer)()
        assert not has_access(t, 'update', user=observer)()
        assert not has_access(t, 'read', user=anon)()
        assert not has_access(t, 'create', user=anon)()
        assert not has_access(t, 'update', user=anon)()

        t.private = False
        assert t.acl == []
        assert has_access(t, 'read', user=admin)()
        assert has_access(t, 'create', user=admin)()
        assert has_access(t, 'update', user=admin)()
        assert has_access(t, 'read', user=developer)()
        assert has_access(t, 'create', user=developer)()
        assert has_access(t, 'update', user=developer)()
        assert has_access(t, 'read', user=creator)()
        assert has_access(t, 'unmoderated_post', user=creator)()
        assert has_access(t, 'create', user=creator)()
        assert not has_access(t, 'update', user=creator)()
        assert has_access(t, 'read', user=observer)()
        assert has_access(t, 'read', user=anon)()
Ejemplo n.º 51
0
    def update_tickets(self, **post_data):
        from forgetracker.tracker_main import get_change_text, get_label

        tickets = Ticket.query.find(
            dict(
                _id={"$in": [ObjectId(id) for id in aslist(post_data["__ticket_ids"])]},
                app_config_id=self.app_config_id,
            )
        ).all()

        fields = set(["status", "private"])
        values = {}
        labels = post_data.get("labels", [])

        for k in fields:
            v = post_data.get(k)
            if v:
                values[k] = v
        assigned_to = post_data.get("assigned_to")
        if assigned_to == "-":
            values["assigned_to_id"] = None
        elif assigned_to:
            user = c.project.user_in_project(assigned_to)
            if user:
                values["assigned_to_id"] = user._id
        private = post_data.get("private")
        if private:
            values["private"] = asbool(private)

        discussion_disabled = post_data.get("discussion_disabled")
        if discussion_disabled:
            values["disabled_discussion"] = asbool(discussion_disabled)

        custom_values = {}
        custom_fields = {}
        for cf in self.custom_fields or []:
            v = post_data.get(cf.name)
            if v:
                custom_values[cf.name] = v
                custom_fields[cf.name] = cf

        changes = {}
        changed_tickets = {}
        for ticket in tickets:
            message = ""
            if labels:
                values["labels"] = self.append_new_labels(ticket.labels, labels.split(","))
            for k, v in sorted(values.iteritems()):
                if k == "assigned_to_id":
                    new_user = User.query.get(_id=v)
                    old_user = User.query.get(_id=getattr(ticket, k))
                    if new_user:
                        message += get_change_text(get_label(k), new_user.display_name, old_user.display_name)
                elif k == "private" or k == "discussion_disabled":

                    def _text(val):
                        if val:
                            return "Yes"
                        else:
                            return "No"

                    message += get_change_text(get_label(k), _text(v), _text(getattr(ticket, k)))
                else:
                    message += get_change_text(get_label(k), v, getattr(ticket, k))
                setattr(ticket, k, v)
            for k, v in sorted(custom_values.iteritems()):

                def cf_val(cf):
                    return ticket.get_custom_user(cf.name) if cf.type == "user" else ticket.custom_fields.get(cf.name)

                cf = custom_fields[k]
                old_value = cf_val(cf)
                if cf.type == "boolean":
                    v = asbool(v)
                ticket.custom_fields[k] = v
                new_value = cf_val(cf)
                message += get_change_text(cf.label, new_value, old_value)
            if message != "":
                changes[ticket._id] = message
                changed_tickets[ticket._id] = ticket
                ticket.discussion_thread.post(message, notify=False)
                ticket.commit()

        filtered_changes = self.filtered_by_subscription(changed_tickets)
        users = User.query.find({"_id": {"$in": filtered_changes.keys()}}).all()

        def changes_iter(user):
            for t_id in filtered_changes.get(user._id, []):
                # mark changes text as safe, thus it wouldn't be escaped in plain-text emails
                # html part of email is handled by markdown and it'll be
                # properly escaped
                yield (changed_tickets[t_id], jinja2.Markup(changes[t_id]))

        mail = dict(
            sender=c.project.app_instance(self.app_config).email_address,
            fromaddr=str(c.user._id),
            reply_to=tg_config["forgemail.return_path"],
            subject="[%s:%s] Mass edit changes by %s"
            % (c.project.shortname, self.app_config.options.mount_point, c.user.display_name),
        )
        tmpl = g.jinja2_env.get_template("forgetracker:data/mass_report.html")
        head = []
        for f, v in sorted(values.iteritems()):
            if f == "assigned_to_id":
                user = User.query.get(_id=v)
                v = user.display_name if user else v
            head.append("- **%s**: %s" % (get_label(f), v))
        for f, v in sorted(custom_values.iteritems()):
            cf = custom_fields[f]
            if cf.type == "user":
                user = User.by_username(v)
                v = user.display_name if user else v
            head.append("- **%s**: %s" % (cf.label, v))
        tmpl_context = {"context": c, "data": {"header": jinja2.Markup("\n".join(["Mass edit changing:", ""] + head))}}
        for user in users:
            tmpl_context["data"].update({"changes": changes_iter(user)})
            mail.update(
                dict(message_id=h.gen_message_id(), text=tmpl.render(tmpl_context), destinations=[str(user._id)])
            )
            mail_tasks.sendmail.post(**mail)

        if self.app_config.options.get("TicketMonitoringType") in ("AllTicketChanges", "AllPublicTicketChanges"):
            monitoring_email = self.app_config.options.get("TicketMonitoringEmail")
            visible_changes = []
            for t_id, t in changed_tickets.items():
                if not t.private or self.app_config.options.get("TicketMonitoringType") == "AllTicketChanges":
                    visible_changes.append((changed_tickets[t_id], jinja2.Markup(changes[t_id])))
            if visible_changes:
                tmpl_context["data"].update({"changes": visible_changes})
                mail.update(
                    dict(message_id=h.gen_message_id(), text=tmpl.render(tmpl_context), destinations=[monitoring_email])
                )
                mail_tasks.sendmail.post(**mail)

        self.invalidate_bin_counts()
        ThreadLocalORMSession.flush_all()
        app = "%s/%s" % (c.project.shortname, self.app_config.options.mount_point)
        count = len(tickets)
        text = "Updated {} ticket{} in {}".format(count, "s" if count != 1 else "", app)
        Notification.post_user(c.user, None, "flash", text=text)