def populate(db): """ Create some data for tests to use. Args: db (sqlalchemy.orm.session.Session): The database session. """ user = User(name=u'guest') db.add(user) anonymous = User(name=u'anonymous') db.add(anonymous) provenpackager = Group(name=u'provenpackager') db.add(provenpackager) packager = Group(name=u'packager') db.add(packager) user.groups.append(packager) release = Release(name=u'F17', long_name=u'Fedora 17', id_prefix=u'FEDORA', version=u'17', dist_tag=u'f17', stable_tag=u'f17-updates', testing_tag=u'f17-updates-testing', candidate_tag=u'f17-updates-candidate', pending_signing_tag=u'f17-updates-testing-signing', pending_testing_tag=u'f17-updates-testing-pending', pending_stable_tag=u'f17-updates-pending', override_tag=u'f17-override', branch=u'f17', state=ReleaseState.current) db.add(release) db.flush() update = create_update(db, [u'bodhi-2.0-1.fc17']) update.type = UpdateType.bugfix update.severity = UpdateSeverity.medium bug = Bug(bug_id=12345) db.add(bug) update.bugs.append(bug) cve = CVE(cve_id=u"CVE-1985-0110") db.add(cve) update.cves.append(cve) comment = Comment(karma=1, text=u"wow. amaze.") db.add(comment) comment.user = user update.comments.append(comment) comment = Comment(karma=0, text=u"srsly. pretty good.", anonymous=True) comment.user = anonymous db.add(comment) update.comments.append(comment) with mock.patch(target='uuid.uuid4', return_value='wat'): update.assign_alias() db.add(update) db.commit()
def populate(db): """ Create some data for tests to use. Args: db (sqlalchemy.orm.session.Session): The database session. """ user = User(name='guest') db.add(user) anonymous = User(name='anonymous') db.add(anonymous) provenpackager = Group(name='provenpackager') db.add(provenpackager) packager = Group(name='packager') db.add(packager) user.groups.append(packager) release = Release(name='F17', long_name='Fedora 17', id_prefix='FEDORA', version='17', dist_tag='f17', stable_tag='f17-updates', testing_tag='f17-updates-testing', candidate_tag='f17-updates-candidate', pending_signing_tag='f17-updates-signing-pending', pending_testing_tag='f17-updates-testing-pending', pending_stable_tag='f17-updates-pending', override_tag='f17-override', branch='f17', state=ReleaseState.current, create_automatic_updates=True, package_manager=PackageManager.unspecified, testing_repository=None) db.add(release) db.flush() # This mock will help us generate a consistent update alias. with mock.patch(target='uuid.uuid4', return_value='wat'): update = create_update(db, ['bodhi-2.0-1.fc17']) update.type = UpdateType.bugfix update.severity = UpdateSeverity.medium bug = Bug(bug_id=12345) db.add(bug) update.bugs.append(bug) comment = Comment(karma=1, text="wow. amaze.") db.add(comment) comment.user = user update.comments.append(comment) comment = Comment(karma=0, text="srsly. pretty good.") comment.user = anonymous db.add(comment) update.comments.append(comment) db.add(update) db.commit()
def test_list_comments_with_multiple_ignore_user(self): another_user = User(name='aUser') self.db.add(another_user) update = Update( user=another_user, request=UpdateRequest.testing, type=UpdateType.enhancement, notes='Just another update.', date_submitted=datetime(1981, 10, 11), requirements='rpmlint', stable_karma=3, unstable_karma=-3, release=Release.query.one() ) self.db.add(update) comment = Comment(karma=1, text='Cool! 😃') comment.user = another_user self.db.add(comment) update.comments.append(comment) self.db.flush() res = self.app.get('/comments/', {"ignore_user": "******"}) body = res.json_body self.assertEqual(len(body['comments']), 1) self.assertNotIn('errors', body) self.assertEqual(body['comments'][0]['text'], 'Cool! 😃')
def test_list_comments_by_multiple_usernames(self): nvr = u'just-testing-1.0-2.fc17' update = Update( title=nvr, request=UpdateRequest.testing, type=UpdateType.enhancement, notes=u'Just another update.', date_submitted=datetime(1981, 10, 11), requirements=u'rpmlint', stable_karma=3, unstable_karma=-3, ) update.release = Release.query.one() self.db.add(update) another_user = User(name=u'aUser') self.db.add(another_user) comment = Comment(karma=1, text=u'Cool! 😃') comment.user = another_user self.db.add(comment) update.comments.append(comment) self.db.flush() res = self.app.get('/comments/', {"user": "******"}) body = res.json_body self.assertEqual(len(body['comments']), 2) self.assertEqual(body['comments'][0]['text'], u'Cool! 😃') self.assertEqual(body['comments'][1]['text'], u'wow. amaze.')
def get_user(request): """ Return a user given by username. Args: request (pyramid.request): The current request. Returns: dict: A dictionary with two keys. "user" maps to a dictionary representation of the User object. "urls" maps to various URLs that describe various other objects related to the user. """ id = request.matchdict.get('name') user = User.get(id) if not user: request.errors.add('body', 'name', 'No such user') request.errors.status = HTTPNotFound.code return user = user.__json__(request) # Throw some extra information in there rurl = request.route_url # Just shorthand urls = { 'comments_by': rurl('comments') + '?user=%s' % id, 'comments_on': rurl('comments') + '?update_owner=%s' % id, 'recent_updates': rurl('updates') + '?user=%s' % id, 'recent_overrides': rurl('overrides') + '?user=%s' % id, 'comments_by_rss': rurl('comments_rss') + '?user=%s' % id, 'comments_on_rss': rurl('comments_rss') + '?update_owner=%s' % id, 'recent_updates_rss': rurl('updates_rss') + '?user=%s' % id, 'recent_overrides_rss': rurl('overrides_rss') + '?user=%s' % id, } return dict(user=user, urls=urls)
def test_remember_me_with_bad_endpoint(self): """Test the post-login hook with a bad openid endpoint""" req = DummyRequest(params={ 'openid.op_endpoint': 'bad_endpoint', }) req.db = self.db def flash(msg): pass req.session.flash = flash info = { 'identity_url': 'http://lmacken.id.fedoraproject.org', 'groups': [u'releng'], } req.registry.settings = self.app_settings try: remember_me(None, req, info) assert False, 'remember_me should have thrown an exception' except Exception: # A ComponentLookupError is thrown because we're doing this outside # of the webapp pass # The user should not exist self.assertIsNone(User.get(u'lmacken', self.db))
def test_list_overrides_by_multiple_usernames(self): release = Release.get('F17') package = RpmPackage(name='just-testing') self.db.add(package) build = RpmBuild(nvr='just-testing-1.0-2.fc17', package=package, release=release) self.db.add(build) another_user = User(name='aUser') self.db.add(another_user) expiration_date = datetime.utcnow() + timedelta(days=1) override = BuildrootOverride(build=build, submitter=another_user, notes='Crazy! 😱', expiration_date=expiration_date) self.db.add(override) self.db.flush() res = self.app.get('/overrides/', {"user": "******"}) body = res.json_body self.assertEqual(len(body['overrides']), 2) override_fake = body['overrides'][0] self.assertEqual(override_fake['build']['nvr'], 'just-testing-1.0-2.fc17') self.assertEqual(override_fake['submitter']['name'], 'aUser') self.assertEqual(override_fake['notes'], 'Crazy! 😱') override_orig = body['overrides'][1] self.assertEqual(override_orig['build']['nvr'], 'bodhi-2.0-1.fc17') self.assertEqual(override_orig['submitter']['name'], 'guest') self.assertEqual(override_orig['notes'], 'blah blah blah')
def setUp(self, *args, **kwargs): super(TestCommentsService, self).setUp(*args, **kwargs) # Add a second update owned by somebody else so we can test karma # policy stuff user2 = User(name='lmacken') self.db.flush() self.db.add(user2) release = self.db.query(Release).filter_by(name='F17').one() update = Update( user=user2, request=UpdateRequest.testing, type=UpdateType.enhancement, notes='Useful details!', release=release, date_submitted=datetime(1984, 11, 2), requirements='rpmlint', stable_karma=3, unstable_karma=-3, ) self.db.add(update) build = RpmBuild(nvr=up2, update=update, package=RpmPackage.query.filter_by(name='bodhi').one()) self.db.add(build) self.db.flush()
def test_list_comments_by_multiple_usernames(self): update = Update(request=UpdateRequest.testing, type=UpdateType.enhancement, notes='Just another update.', date_submitted=datetime(1981, 10, 11), requirements='rpmlint', stable_karma=3, unstable_karma=-3, release=Release.query.one()) self.db.add(update) another_user = User(name='aUser') self.db.add(another_user) comment = Comment(karma=1, text='Cool! 😃') comment.user = another_user self.db.add(comment) update.comments.append(comment) self.db.flush() res = self.app.get('/comments/', {"user": "******"}) body = res.json_body assert len(body['comments']) == 2 assert body['comments'][0]['text'] == 'Cool! 😃' assert body['comments'][1]['text'] == 'wow. amaze.'
def test_list_comments_by_multiple_update_owners(self): another_user = User(name='aUser') self.db.add(another_user) update = Update( user=another_user, request=UpdateRequest.testing, type=UpdateType.enhancement, notes='Just another update.', date_submitted=datetime(1981, 10, 11), requirements='rpmlint', stable_karma=3, unstable_karma=-3, release=Release.query.one() ) self.db.add(update) comment = Comment(karma=1, text='Cool! 😃') comment.user = another_user self.db.add(comment) update.comments.append(comment) self.db.flush() res = self.app.get('/comments/', {"update_owner": "guest,aUser"}) body = res.json_body self.assertEqual(len(body['comments']), 3) comment = body['comments'][0] self.assertEqual(comment['text'], 'Cool! 😃') comment = body['comments'][1] self.assertEqual(comment['text'], 'srsly. pretty good.')
def test_get_single_user_with_nonstandard_characters(self): """Test that we don't receive a 404 page with bot usernames.""" user = User(name='bot/a.bad.name') self.db.add(user) self.db.flush() res = self.app.get('/users/bot/a.bad.name') assert res.json_body['user']['name'] == 'bot/a.bad.name'
def create_or_update_user(db, username, email, groups): """Create or update a user in the database. Args: db (sqlalchemy.orm.session.Session): The database session. username (str): The username to create or update email (str): The user's email address groups (list(str)): A list of group names the user belongs to, that will be synced. Returns: bodhi.server.models.User: The user instance. """ # Find the user in our database. Create it if it doesn't exist. user = db.query(User).filter_by(name=username).first() if not user: user = User(name=username, email=email) db.add(user) db.flush() else: # Update email address if the address changed if user.email != email: user.email = email db.flush() # Keep track of what groups the user is a member of for group_name in groups: # Drop empty group names https://github.com/fedora-infra/bodhi/issues/306 if not group_name.strip(): continue group = db.query(Group).filter_by(name=group_name).first() if not group: group = Group(name=group_name) db.add(group) db.flush() if group not in user.groups: log.info('Adding %s to %s group', user.name, group.name) user.groups.append(group) # See if the user was removed from any groups for group in user.groups: if group.name not in groups: log.info('Removing %s from %s group', user.name, group.name) user.groups.remove(group) return user
def test_list_overrides_by_username_without_override(self): self.db.add(User(name='bochecha')) self.db.flush() res = self.app.get('/overrides/', {'user': '******'}) body = res.json_body self.assertEqual(len(body['overrides']), 0)
def test_list_comments_by_update_owner_with_none(self): user = User(name='ralph') self.db.add(user) self.db.flush() res = self.app.get('/comments/', {"update_owner": "ralph"}) body = res.json_body self.assertEqual(len(body['comments']), 0) self.assertNotIn('errors', body)
def test_list_comments_by_update_owner_with_none(self): user = User(name='ralph') self.db.add(user) self.db.flush() res = self.app.get('/comments/', {"update_owner": "ralph"}) body = res.json_body assert len(body['comments']) == 0 assert 'errors' not in body
def test_remember_me(self): """Test the post-login hook""" req = DummyRequest( params={ 'openid.op_endpoint': self.app_settings['openid.provider'], }) req.db = self.db req.session = {'came_from': '/'} info = { 'identity_url': 'http://lmacken.id.fedoraproject.org', 'groups': [u'releng'], 'sreg': { 'email': u'[email protected]' }, } req.registry.settings = self.app_settings # Ensure the user doesn't exist yet self.assertIsNone(User.get(u'lmacken', self.db)) self.assertIsNone(Group.get(u'releng', self.db)) remember_me(None, req, info) # The user should now exist, and be a member of the releng group user = User.get(u'lmacken', self.db) self.assertEquals(user.name, u'lmacken') self.assertEquals(user.email, u'[email protected]') self.assertEquals(len(user.groups), 1) self.assertEquals(user.groups[0].name, u'releng') # Pretend the user has been removed from the releng group info['groups'] = [] req.session = {'came_from': '/'} remember_me(None, req, info) user = User.get(u'lmacken', self.db) self.assertEquals(len(user.groups), 0) self.assertEquals(len(Group.get(u'releng', self.db).users), 0)
def test_edit_stack_with_no_user_privs(self, *args): user = User(name=u'bob') self.db.add(user) self.db.add(RpmPackage(name=u'gnome-music')) self.db.commit() self.stack.users.append(user) self.db.commit() attrs = {'name': 'GNOME', 'packages': 'gnome-music gnome-shell', 'csrf_token': self.get_csrf_token()} res = self.app.post("/stacks/", attrs, status=403) body = res.json_body self.assertEquals(body['status'], 'error') self.assertEquals(body['errors'][0]['description'], 'guest does not have privileges to modify the GNOME stack')
def test_existing_user(self, caplog): """Test Koji build user existing in DB.""" caplog.set_level(logging.DEBUG) expected_username = base.buildsys.DevBuildsys._build_data['owner_name'] # ensure user with expected name exists user = self.db.query(User).filter_by(name=expected_username).first() if not user: user = User(name=expected_username) self.db.add(user) self.db.flush() assert (f"Creating bodhi user for '{expected_username}'." not in caplog.messages)
def test_existing_user(self, caplog): """Test Koji build user existing in DB.""" caplog.set_level(logging.DEBUG) expected_username = base.buildsys.DevBuildsys._build_data['owner_name'] # ensure user with expected name exists user = self.db.query(User).filter_by(name=expected_username).first() if not user: user = User(name=expected_username) self.db.add(user) self.db.flush() with mock.patch('bodhi.server.models.handle_update'): with mock_sends(update_schemas.UpdateReadyForTestingV1): self.handler(self.sample_message) assert (f"Creating bodhi user for '{expected_username}'." not in caplog.messages)
def groupfinder(userid, request): """ Return a list of strings describing the groups the request's user is a member of. The strings are of the format group:<group_name>, so this might return something like this as an example: ['group:packager', 'group:bodhiadmin'] Args: userid (str): The user's id. request (pyramid.request.Request): The current web request. Returns: list or None: A list of the user's groups, or None if the user is not authenticated. """ from bodhi.server.models import User if request.user: user = User.get(request.user.name) return ['group:' + group.name for group in user.groups]
def save_stack(request): """ Save a stack. Args: request (pyramid.request): The current web request. Returns: dict: A dictionary with key "stack" that indexes the newly created Stack. """ data = request.validated db = request.db user = User.get(request.user.name) # Fetch or create the stack stack = Stack.get(data['name']) if not stack: stack = Stack(name=data['name'], users=[user]) db.add(stack) db.flush() if stack.users or stack.groups: if user in stack.users: log.info('%s is an owner of the %s', user.name, stack.name) else: for group in user.groups: if group in stack.groups: log.info('%s is a member of the %s group', user.name, stack.name) break else: log.warning('%s is not an owner of the %s stack', user.name, stack.name) log.debug('owners = %s; groups = %s', stack.users, stack.groups) request.errors.add('body', 'name', '%s does not have privileges' ' to modify the %s stack' % (user.name, stack.name)) request.errors.status = HTTPForbidden.code return # Update the stack description desc = data['description'] if desc: stack.description = desc # Update the stack requirements # If the user passed in no value at all for requirements, then use # the site defaults. If, however, the user passed in the empty string, we # assume they mean *really*, no requirements so we leave the value null. reqs = data['requirements'] if reqs is None: stack.requirements = config.get('site_requirements') elif reqs: stack.requirements = reqs stack.update_relationship('users', User, data, db) stack.update_relationship('groups', Group, data, db) # We make a special case out of packages here, since when a package is # added to a stack, we want to give it the same requirements as the stack # has. See https://github.com/fedora-infra/bodhi/issues/101 new, same, rem = stack.update_relationship('packages', Package, data, db) if stack.requirements: additional = list(tokenize(stack.requirements)) for name in new: package = Package.get(name) original = package.requirements original = [] if not original else list(tokenize(original)) package.requirements = " ".join(list(set(original + additional))) log.info('Saved %s stack', data['name']) notifications.publish(topic='stack.save', msg=dict( stack=stack, agent=user.name)) return dict(stack=stack)
def save_override(request): """ Create or edit a buildroot override. This entails either creating a new buildroot override, or editing an existing one. To edit an existing buildroot override, the buildroot override's original id needs to be specified in the ``edited`` parameter. Args: request (pyramid.request): The current web request. Returns: dict: The new or edited override. """ data = request.validated edited = data.pop("edited") caveats = [] try: submitter = User.get(request.user.name) if edited is None: builds = data['builds'] overrides = [] if len(builds) > 1: caveats.append({ 'name': 'nvrs', 'description': 'Your override submission was ' 'split into %i.' % len(builds) }) for build in builds: log.info("Creating a new buildroot override: %s" % build.nvr) existing_override = BuildrootOverride.get(build.id) if existing_override: if not existing_override.expired_date: data['expiration_date'] = max( existing_override.expiration_date, data['expiration_date']) new_notes = f"""{data['notes']} _____________ _@{existing_override.submitter.name} ({existing_override.submission_date.strftime('%b %d, %Y')})_ {existing_override.notes}""" # Truncate notes at 2000 chars if len(new_notes) > 2000: new_notes = new_notes[:1972] + '(...)\n___Notes truncated___' overrides.append( BuildrootOverride.edit( request, edited=build, submitter=submitter, submission_date=datetime.now(), notes=new_notes, expiration_date=data['expiration_date'], expired=None, )) else: overrides.append( BuildrootOverride.new( request, build=build, submitter=submitter, notes=data['notes'], expiration_date=data['expiration_date'], )) if len(builds) > 1: result = dict(overrides=overrides) else: result = overrides[0] else: log.info("Editing buildroot override: %s" % edited) edited = Build.get(edited) if edited is None: request.errors.add('body', 'edited', 'No such build') return result = BuildrootOverride.edit( request, edited=edited, submitter=submitter, notes=data["notes"], expired=data["expired"], expiration_date=data["expiration_date"]) if not result: # Some error inside .edit(...) return except Exception as e: log.exception(e) request.errors.add('body', 'override', 'Unable to save buildroot override: %s' % e) return if not isinstance(result, dict): result = result.__json__() result['caveats'] = caveats return result
def setUp(self, *args, **kwargs): super(TestFrontpageView, self).setUp(*args, **kwargs) def _add_updates(updateslist, user, release, packagesuffix): """Private method that adds updates to the database for testing """ count = 0 for i in updateslist: for j in i[1]: for k in range(0, j[1]): update = Update( title=u'bodhi-2.0-1%s.%s' % (str(count), packagesuffix), user=user, status=i[0], type=j[0], notes=u'Useful details!', release=release, date_submitted=datetime(1984, 11, 2), requirements=u'rpmlint', stable_karma=3, unstable_karma=-3, ) self.db.add(update) self.db.flush() count = count + 1 user2 = User(name=u'dudemcpants') self.db.flush() self.db.add(user2) release = Release(name=u'F18', long_name=u'Fedora 18', id_prefix=u'FEDORA', version=u'18', dist_tag=u'f18', stable_tag=u'f18-updates', testing_tag=u'f18-updates-testing', candidate_tag=u'f18-updates-candidate', pending_signing_tag=u'f18-updates-testing-signing', pending_testing_tag=u'f18-updates-testing-pending', pending_stable_tag=u'f18-updates-pending', override_tag=u'f18-override', branch=u'f18', state=ReleaseState.pending) self.db.add(release) currentrelease = self.db.query(Release).filter_by(name=u'F17').one() addedupdates = [[ UpdateStatus.pending, [[UpdateType.security, 5], [UpdateType.bugfix, 4], [UpdateType.enhancement, 3], [UpdateType.newpackage, 2]] ], [ UpdateStatus.testing, [[UpdateType.security, 15], [UpdateType.bugfix, 14], [UpdateType.enhancement, 13], [UpdateType.newpackage, 12]] ], [ UpdateStatus.stable, [[UpdateType.security, 25], [UpdateType.bugfix, 24], [UpdateType.enhancement, 23], [UpdateType.newpackage, 22]] ]] _add_updates(addedupdates, user2, currentrelease, "fc17") pendingrelease = self.db.query(Release).filter_by(name=u'F18').one() addedupdates2 = [[ UpdateStatus.pending, [[UpdateType.security, 2], [UpdateType.bugfix, 2], [UpdateType.enhancement, 2], [UpdateType.newpackage, 2]] ], [ UpdateStatus.testing, [[UpdateType.security, 3], [UpdateType.bugfix, 3], [UpdateType.enhancement, 3], [UpdateType.newpackage, 3]] ], [ UpdateStatus.stable, [[UpdateType.security, 4], [UpdateType.bugfix, 4], [UpdateType.enhancement, 4], [UpdateType.newpackage, 4]] ]] _add_updates(addedupdates2, user2, pendingrelease, "fc18") self.db.flush() Release._tag_cache = None
def setup_method(self, method): super(TestUsersService, self).setup_method(method) user = User(name='bodhi') self.db.add(user) self.db.flush()
def __call__(self, message: fedora_messaging.api.Message) -> None: """Create updates from appropriately tagged builds. Args: message: The message we are processing. """ body = message.body missing = [] for mandatory in ('tag', 'build_id', 'name', 'version', 'release'): if mandatory not in body: missing.append(mandatory) if missing: log.debug( f"Received incomplete tag message. Missing: {', '.join(missing)}" ) return btag = body['tag'] bnvr = '{name}-{version}-{release}'.format(**body) koji = buildsys.get_session() kbuildinfo = koji.getBuild(bnvr) if not kbuildinfo: log.debug(f"Can't find Koji build for {bnvr}.") return if 'nvr' not in kbuildinfo: log.debug(f"Koji build info for {bnvr} doesn't contain 'nvr'.") return if 'owner_name' not in kbuildinfo: log.debug( f"Koji build info for {bnvr} doesn't contain 'owner_name'.") return if kbuildinfo['owner_name'] in config.get( 'automatic_updates_blacklist'): log.debug( f"{bnvr} owned by {kbuildinfo['owner_name']} who is listed in " "automatic_updates_blacklist, skipping.") return # some APIs want the Koji build info, some others want the same # wrapped in a larger (request?) structure rbuildinfo = { 'info': kbuildinfo, 'nvr': kbuildinfo['nvr'].rsplit('-', 2), } with self.db_factory() as dbsession: rel = dbsession.query(Release).filter_by( create_automatic_updates=True, candidate_tag=btag).first() if not rel: log.debug( f"Ignoring build being tagged into {btag!r}, no release configured for " "automatic updates for it found.") return bcls = ContentType.infer_content_class(Build, kbuildinfo) build = bcls.get(bnvr) if build and build.update: log.info( f"Build, active update for {bnvr} exists already, skipping." ) return if not build: log.debug(f"Build for {bnvr} doesn't exist yet, creating.") # Package.get_or_create() infers content type already log.debug("Getting/creating related package object.") pkg = Package.get_or_create(dbsession, rbuildinfo) log.debug("Creating build object, adding it to the DB.") build = bcls(nvr=bnvr, package=pkg, release=rel) dbsession.add(build) owner_name = kbuildinfo['owner_name'] user = User.get(owner_name) if not user: log.debug(f"Creating bodhi user for '{owner_name}'.") # Leave email, groups blank, these will be filled # in or updated when they log into Bodhi next time, see # bodhi.server.security:remember_me(). user = User(name=owner_name) dbsession.add(user) log.debug(f"Creating new update for {bnvr}.") changelog = build.get_changelog(lastupdate=True) if changelog: notes = f"""Automatic update for {bnvr}. ##### **Changelog** ``` {changelog} ```""" else: notes = f"Automatic update for {bnvr}." update = Update( release=rel, builds=[build], notes=notes, type=UpdateType.unspecified, stable_karma=3, unstable_karma=-3, autokarma=False, user=user, status=UpdateStatus.pending, ) # Comment on the update that it was automatically created. update.comment( dbsession, str("This update was automatically created"), author="bodhi", ) update.add_tag(update.release.pending_signing_tag) log.debug("Adding new update to the database.") dbsession.add(update) log.debug("Committing changes to the database.") dbsession.commit()
def query_comments(request): """ Search for comments matching given search parameters. Args: request (pyramid.request): The current request. Return: dict: A dictionary with the following key-value pairs: comments: An iterable with the current page of matched comments. page: The current page number. pages: The total number of pages. rows_per_page: The number of rows per page. total: The number of items matching the search terms. chrome: A boolean indicating whether to paginate or not. """ db = request.db data = request.validated query = db.query(Comment) like = data.get('like') if like is not None: query = query.filter(or_(*[Comment.text.like('%%%s%%' % like)])) packages = data.get('packages') if packages is not None: query = query\ .join(Comment.update)\ .join(Update.builds)\ .join(Build.package) query = query.filter(or_(*[Build.package == pkg for pkg in packages])) since = data.get('since') if since is not None: query = query.filter(Comment.timestamp >= since) updates = data.get('updates') if updates is not None: query = query.filter(or_(*[Comment.update == u for u in updates])) update_owner = data.get('update_owner') if update_owner is not None: query = query.join(Comment.update) query = query.filter(or_(*[Update.user == u for u in update_owner])) ignore_user = data.get('ignore_user') if ignore_user is not None: query = query.filter(and_(*[Comment.user != u for u in ignore_user])) # don't show bodhi user comments in the web interface if data.get("chrome"): query = query.filter(and_(*[Comment.user != User.get('bodhi')])) user = data.get('user') if user is not None: query = query.filter(or_(*[Comment.user == u for u in user])) query = query.order_by(Comment.timestamp.desc()) # We can't use ``query.count()`` here because it is naive with respect to # all the joins that we're doing above. count_query = query.with_labels().statement\ .with_only_columns([func.count(distinct(Comment.id))])\ .order_by(None) total = db.execute(count_query).scalar() page = data.get('page') rows_per_page = data.get('rows_per_page') pages = int(math.ceil(total / float(rows_per_page))) query = query.offset(rows_per_page * (page - 1)).limit(rows_per_page) return dict( comments=query.all(), page=page, pages=pages, rows_per_page=rows_per_page, total=total, chrome=data.get('chrome'), )
def __call__(self, message: fedora_messaging.api.Message) -> None: """Create updates from appropriately tagged builds. Args: message: The message we are processing. """ body = message.body missing = [] for mandatory in ('tag', 'build_id', 'name', 'version', 'release'): if mandatory not in body: missing.append(mandatory) if missing: log.debug( f"Received incomplete tag message. Missing: {', '.join(missing)}" ) return btag = body['tag'] bnvr = '{name}-{version}-{release}'.format(**body) koji = buildsys.get_session() kbuildinfo = koji.getBuild(bnvr) if not kbuildinfo: log.debug(f"Can't find Koji build for {bnvr}.") return if 'nvr' not in kbuildinfo: log.debug(f"Koji build info for {bnvr} doesn't contain 'nvr'.") return if 'owner_name' not in kbuildinfo: log.debug( f"Koji build info for {bnvr} doesn't contain 'owner_name'.") return if kbuildinfo['owner_name'] in config.get( 'automatic_updates_blacklist'): log.debug( f"{bnvr} owned by {kbuildinfo['owner_name']} who is listed in " "automatic_updates_blacklist, skipping.") return # some APIs want the Koji build info, some others want the same # wrapped in a larger (request?) structure rbuildinfo = { 'info': kbuildinfo, 'nvr': kbuildinfo['nvr'].rsplit('-', 2), } with self.db_factory() as dbsession: rel = dbsession.query(Release).filter_by( create_automatic_updates=True, candidate_tag=btag).first() if not rel: log.debug( f"Ignoring build being tagged into {btag!r}, no release configured for " "automatic updates for it found.") return bcls = ContentType.infer_content_class(Build, kbuildinfo) build = bcls.get(bnvr) if build and build.update: log.info( f"Build, active update for {bnvr} exists already, skipping." ) return if not build: log.debug(f"Build for {bnvr} doesn't exist yet, creating.") # Package.get_or_create() infers content type already log.debug("Getting/creating related package object.") pkg = Package.get_or_create(dbsession, rbuildinfo) log.debug("Creating build object, adding it to the DB.") build = bcls(nvr=bnvr, package=pkg, release=rel) dbsession.add(build) owner_name = kbuildinfo['owner_name'] user = User.get(owner_name) if not user: log.debug(f"Creating bodhi user for '{owner_name}'.") # Leave email, groups blank, these will be filled # in or updated when they log into Bodhi next time, see # bodhi.server.security:remember_me(). user = User(name=owner_name) dbsession.add(user) log.debug(f"Creating new update for {bnvr}.") try: changelog = build.get_changelog(lastupdate=True) except ValueError: # Often due to bot-generated builds # https://github.com/fedora-infra/bodhi/issues/4146 changelog = None except Exception: # Re-raise exception, so that the message can be re-queued raise closing_bugs = [] if changelog: log.debug("Adding changelog to update notes.") notes = f"""Automatic update for {bnvr}. ##### **Changelog** ``` {changelog} ```""" if rel.name not in config.get('bz_exclude_rels'): for b in re.finditer(config.get('bz_regex'), changelog, re.IGNORECASE): idx = int(b.group(1)) log.debug(f'Adding bug #{idx} to the update.') bug = Bug.get(idx) if bug is None: bug = Bug(bug_id=idx) dbsession.add(bug) dbsession.flush() if bug not in closing_bugs: closing_bugs.append(bug) else: notes = f"Automatic update for {bnvr}." update = Update( release=rel, builds=[build], bugs=closing_bugs, notes=notes, type=UpdateType.unspecified, stable_karma=3, unstable_karma=-3, autokarma=False, user=user, status=UpdateStatus.pending, critpath=Update.contains_critpath_component([build], rel.branch), ) # Comment on the update that it was automatically created. update.comment( dbsession, str("This update was automatically created"), author="bodhi", ) update.add_tag(update.release.pending_signing_tag) log.debug("Adding new update to the database.") dbsession.add(update) log.debug("Flushing changes to the database.") dbsession.flush() # Obsolete older updates which may be stuck in testing due to failed gating try: update.obsolete_older_updates(dbsession) except Exception as e: log.error(f'Problem obsoleting older updates: {e}') alias = update.alias buglist = [b.bug_id for b in update.bugs] # This must be run after dbsession is closed so changes are committed to db work_on_bugs_task.delay(alias, buglist)
def save_override(request): """ Create or edit a buildroot override. This entails either creating a new buildroot override, or editing an existing one. To edit an existing buildroot override, the buildroot override's original id needs to be specified in the ``edited`` parameter. Args: request (pyramid.request): The current web request. Returns: dict: The new or edited override. """ data = request.validated edited = data.pop("edited") caveats = [] try: submitter = User.get(request.user.name) if edited is None: builds = data['builds'] overrides = [] if len(builds) > 1: caveats.append({ 'name': 'nvrs', 'description': 'Your override submission was ' 'split into %i.' % len(builds) }) for build in builds: log.info("Creating a new buildroot override: %s" % build.nvr) if BuildrootOverride.get(build.id): request.errors.add('body', 'builds', 'Buildroot override for %s already exists' % build.nvr) return else: overrides.append(BuildrootOverride.new( request, build=build, submitter=submitter, notes=data['notes'], expiration_date=data['expiration_date'], )) if len(builds) > 1: result = dict(overrides=overrides) else: result = overrides[0] else: log.info("Editing buildroot override: %s" % edited) edited = Build.get(edited) if edited is None: request.errors.add('body', 'edited', 'No such build') return result = BuildrootOverride.edit( request, edited=edited, submitter=submitter, notes=data["notes"], expired=data["expired"], expiration_date=data["expiration_date"]) if not result: # Some error inside .edit(...) return except Exception as e: log.exception(e) request.errors.add('body', 'override', 'Unable to save buildroot override: %s' % e) return if not isinstance(result, dict): result = result.__json__() result['caveats'] = caveats return result
def setUp(self, *args, **kwargs): super(TestReleasesHTML, self).setUp(*args, **kwargs) def _add_updates(updateslist, user, release, packagesuffix): """Private method that adds updates to the database for testing """ count = 0 for i in updateslist: for j in i[1]: for k in range(0, j[1]): update = Update( user=user, status=i[0], type=j[0], notes='Useful details!', release=release, date_submitted=datetime(1984, 11, 2), requirements='rpmlint', stable_karma=3, unstable_karma=-3, ) self.db.add(update) self.db.commit() count = count + 1 user2 = User(name='dudemcpants') self.db.flush() self.db.add(user2) release = Release(name='F18', long_name='Fedora 18', id_prefix='FEDORA', version='18', dist_tag='f18', stable_tag='f18-updates', testing_tag='f18-updates-testing', candidate_tag='f18-updates-candidate', pending_signing_tag='f18-updates-testing-signing', pending_testing_tag='f18-updates-testing-pending', pending_stable_tag='f18-updates-pending', override_tag='f18-override', branch='f18', state=ReleaseState.pending) self.db.add(release) currentrelease = self.db.query(Release).filter_by(name='F17').one() addedupdates = [[ UpdateStatus.pending, [[UpdateType.security, 5], [UpdateType.bugfix, 4], [UpdateType.enhancement, 3], [UpdateType.newpackage, 2]] ], [ UpdateStatus.testing, [[UpdateType.security, 15], [UpdateType.bugfix, 14], [UpdateType.enhancement, 13], [UpdateType.newpackage, 12]] ], [ UpdateStatus.stable, [[UpdateType.security, 25], [UpdateType.bugfix, 24], [UpdateType.enhancement, 23], [UpdateType.newpackage, 22]] ]] with fml_testing.mock_sends(*[api.Message] * 54): _add_updates(addedupdates, user2, currentrelease, "fc17") pendingrelease = self.db.query(Release).filter_by(name='F18').one() addedupdates2 = [[ UpdateStatus.pending, [[UpdateType.security, 2], [UpdateType.bugfix, 2], [UpdateType.enhancement, 2], [UpdateType.newpackage, 2]] ], [ UpdateStatus.testing, [[UpdateType.security, 3], [UpdateType.bugfix, 3], [UpdateType.enhancement, 3], [UpdateType.newpackage, 3]] ], [ UpdateStatus.stable, [[UpdateType.security, 4], [UpdateType.bugfix, 4], [UpdateType.enhancement, 4], [UpdateType.newpackage, 4]] ]] with fml_testing.mock_sends(*[api.Message] * 12): _add_updates(addedupdates2, user2, pendingrelease, "fc18") self.db.flush() # Clear the caches Release._tag_cache = None generic._generate_home_page_stats.invalidate()
def setUp(self): super(TestUsersService, self).setUp() user = User(name=u'bodhi') self.db.add(user) self.db.flush()