예제 #1
0
    def name(self, collctn):
        '''Return a page with information on a particular Collection

        :arg collctn: Collection shortname
        '''
        ### FIXME: Want to return additional info:
        # date it was created (join log table: creation date)
        # The initial import doesn't have this information, though.
        try:
            #pylint:disable-msg=E1101
            collection = Collection.by_simple_name(collctn)
        except InvalidRequestError:
            # Either the name doesn't exist or somehow it references more than
            # one value
            flash(_('The collection name you were linked to, %(collctn)s,'
                    ' does not exist.  If you received this error from'
                    ' a link on the fedoraproject.org website, please'
                    ' report it.') % {'collctn': collctn})
            if request_format() == 'json':
                error = dict(exc='InvalidCollection')
            else:
                error = dict(title=_('%(app)s -- Invalid Collection Name') % {
                            'app': self.app_title},
                        tg_template='pkgdb.templates.errors')
            return error

        # Why do we reformat the data returned from the database?
        # 1) We don't need all the information in the collection object
        # 2) We need statusname which is not in the specific table.
        collection_entry = {'name': collection.name,
                'version': collection.version,
                'owner': collection.owner,
                'summary': collection.summary,
                'description': collection.description,
                'statusname': collection.status.locale['C'].statusname
                }

        # Retrieve the package list for this collection
        # pylint:disable-msg=E1101
        packages = select((PackageTable,), and_(Package.id==PackageListing.packageid,
                PackageListing.collectionid==collection.id,
                Package.statuscode!=STATUS['Removed']),
                order_by=(Package.name,)).execute()
        # pylint:enable-msg=E1101

        return dict(title='%s -- %s %s' % (self.app_title, collection.name,
            collection.version), collection=collection_entry,
            packages=packages)
예제 #2
0
    def default(self, buildName=None, repo='F-11-i386'):
        '''Retrieve PackageBuild by their name.

        This method returns general packagebuild/rpm information about a
        package like: version, release, size, last changelog message,
        committime etc. This information comes from yum and is stored in
        the pkgdb.

        :arg buildName: Name of the packagebuild/rpm to lookup
        :arg repo: shortname of the repository to look in
        '''
        if buildName == None:
            raise redirect('/packages/list/')

        #pylint:disable-msg=E1101
        #builds_query = PackageBuild.query.filter_by(name=buildName)
        #pylint:enable-msg=E1101

        # look for The One packagebuild
        try:
            #pylint:disable-msg=E1101
            build = builds_query.join(PackageBuild.repos).filter(
                Repo.shortname==repo).one()
        except:
            error = dict(status=False,
                         title=_('%(app)s -- Invalid PackageBuild Name') % {
                             'app': self.app_title},
                             message=_('The package build you were linked to'
                             ' (%(pkg)s) does not appear in the Package '
                             ' Database. If you received this error from a link'
                             ' on the fedoraproject.org website, please report'
                             ' it.') % {'pkg': buildName})
            if request_format() != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
                return error
        other_repos = []
        arches = set()
        for b in builds_query.all():
            other_repos.append(b.repo)
            arches.add(b.architecture)
        other_repos.remove(build.repo)
        


        return dict(title=_('%(title)s -- %(pkg)s') % {
            'title': self.app_title, 'pkg': buildName},
                    repo=repo, build=build, other_repos=other_repos,
                    arches=arches)
예제 #3
0
    def __convert(self, bug):
        """Convert bugs from the raw form retrieved from python-bugzilla to
        one that is consumable by a normal python program.

        This involves converting byte strings to unicode type and substituting
        any private URLs returned into a public URL.  (This occurs when we
        have to call bugzilla via one name on the internal network but someone
        clicking on the link in a web page needs to use a different address.)

        :arg bug: A bug record returned from the python-bugzilla interface.
        """
        if not isinstance(bug, Bug):
            raise TypeError(_("Can only store bugzilla.Bug type"))
        if self.query_url != self.public_url:
            bug.url = bug.url.replace(self.query_url, self.public_url)

        bug.bug_status = to_unicode(bug.bug_status)
        bug.short_desc = to_unicode(bug.short_desc)
        bug.product = to_unicode(bug.product)
        return {
            "url": bug.url,
            "bug_status": bug.bug_status,
            "short_desc": bug.short_desc,
            "bug_id": bug.bug_id,
            "product": bug.product,
        }
예제 #4
0
    def _mass_branch(self, to_branch, devel_branch, pkgs, author_name,
            author_email):
        '''Performs a mass branching.  Intended to run in the background.

        :arg to_branch: Branch to put new PackageListings on
        :arg devel_branch: Branch for devel, where we're branching from
        :arg pkgs: List of packages to branch
        :arg author_name: username of person making the branch
        :arg author_email: email of person making the branch

        This method branches all the packages given to it from devel_branch to
        to_branch.  It subdivides the package list and branches each set in a
        forked process.  This is done to keep memory usage reasonable.  After
        it finishes, it emails the user who started the process the results of
        the branching.
        '''
        unbranched = []
        pkg_idx = 0
        # Split this up and fork so we don't blow out all our memory
        for pkg_idx in range(MASS_BRANCH_SET, len(pkgs), MASS_BRANCH_SET):
            unbranched.extend(self._mass_branch_worker(to_branch, devel_branch,
                pkgs[pkg_idx - MASS_BRANCH_SET:pkg_idx], author_name))
        unbranched.extend(self._mass_branch_worker(to_branch, devel_branch,
            pkgs[pkg_idx:], author_name))


        if unbranched:
            # Uh oh, there were packages which weren't branched.  Tell the
            # user
            msg = _('%(count)s/%(num)s packages were unbranched for' \
                    ' %(branch)s\n') % {'count': len(unbranched),
                            'num': len(pkgs), 'branch': to_branch.branchname}
            msg = msg + '\n'.join(unbranched)
        else:
            num_branched = len(pkgs) - len(unbranched)
            msg = _('Succesfully branched all %(num)s packages') % \
                    {'num': num_branched}

        # Send an email to the user to tell them how things turned out
        eventlogger = EventLogger()
        eventlogger.send_msg(msg, _('Mass branching status for %(branch)s') %
                {'branch': to_branch.branchname},
                (author_email,))
예제 #5
0
    def info(self, fasname=None):
        '''Return some info and links for the user.

        Currently this page does nothing.  Eventually we want it to return an
        overview of what the user can do.  A TODO queue of people/packages
        they need to approve.  Links to FAS. Etc.

        :kwarg fasname: If given, the name of hte user to display information
            for.  Defaults to the logged in user.
        '''
        # If fasname is blank, ask for auth, we assume they want their own?
        if fasname == None:
            if identity.current.anonymous:
                raise identity.IdentityFailure(
                        _('You must be logged in to view your information'))
            else:
                fasname = identity.current.user_name

        page_title = _('%(app)s -- %(name)s -- Info') % {
                'app': self.app_title, 'name': fasname}
        return dict(title=page_title, fasname=fasname)
예제 #6
0
    def index(self):
        '''Advanced package search.

        Provides a form with multiple fields for a comprehensive package
        search.

        :collections: list of pkgdb collections
        '''
        # a little helper so we don't have to write/update form selects manually
        #pylint:disable-msg=E1101
        collections = select([Collection.id,
                    Collection.name, Collection.version]).execute()
        #pylint:enable-msg=E1101
        return dict(title=_('%(app)s -- Advanced Search') % {
            'app': self.app_title}, collections=collections)
예제 #7
0
    def __getitem__(self, status_id):
        '''Return the other half of status from memcache or the database

        :arg status_id: This can be either a statuscode or a statusname.
            If it's a statusname, the statuscode will be returned.  If
            it's a statusname, the statuscode will be returned.
        '''
        if isinstance(status_id, basestring):
            # Have a statusname, looking for an id

            # First ask memcache server for the value
            mc_id = 'pkgdb:status:%s' % Hasher(status_id).hexdigest()
            status_value = MEMCACHE.get(mc_id)

            if not status_value:
                status = session.query(StatusTranslation).filter(
                    and_(
                        StatusTranslationTable.c.language == 'C',
                        StatusTranslationTable.c.statusname == status_id
                    )
                ).one()
        else:
            # Have an id, look for a statusname

            # Ask memcache server for the value
            mc_id = 'pkgdb:status:%s' % str(status_id)
            status_value = MEMCACHE.get(mc_id)

            if not status_value:
                try:
                    status = session.query(StatusTranslation).filter(and_(
                        StatusTranslation.language == 'C',
                        StatusTranslation.statuscodeid == status_id)).one()
                except DataError:
                    # If status_id was not an integer we get a DataError.  In
                    # that case, we know we won't find the value we want
                    status = None

        if not status_value:
            if not status:
                raise KeyError(_('Unknown status: %(status)s') %
                               {'status': status_id})

            status_value = status.statuscodeid
            # Save in memcache for the next status lookup
            MEMCACHE.set(mc_id, status_value, self.timeout)

        return status_value
예제 #8
0
    def _send_msg(self, msg, subject, recipients, from_addr=None):
        '''Send an email from the packagedb.'''
        if not from_addr:
            from_addr = self.MAILFROM

        if config.get('mail.on', False):
            for person in recipients:
                email = turbomail.Message(from_addr, person,
                        '[pkgdb] %s' % (subject,))
                email.plain = msg
                turbomail.enqueue(email)
        else:
            LOG.debug(_('Would have sent: %(subject)s') % {
                'subject': subject.encode('ascii', 'replace')})
            LOG.debug('To: %s' % recipients)
            LOG.debug('From: %s %s' %
                    (from_addr[0].encode('ascii', 'replace'),
                    from_addr[1].encode('ascii', 'replace')))
            LOG.debug('%s' % msg.encode('ascii', 'replace'))
예제 #9
0
    def orphans(self, eol=None):
        '''List orphaned packages.

        :kwarg eol: If set, list packages that are in EOL distros.
        :returns: A list of packages.
        '''
        ### FIXME: Replace with a validator
        if not eol or eol.lower() in ('false', 'f', '0'):
            eol = False
        else:
            eol = bool(eol)

        page_title = _('%(app)s -- Orphaned Packages') % {'app': self.app_title}

        #pylint:disable-msg=E1101
        query = Package.query.join('listings2').distinct().filter(
                    PackageListing.statuscode==STATUS['Orphaned'])
        #pylint:enable-msg=E1101
        if not eol:
            # We don't want EOL releases, filter those out of each clause
            #pylint:disable-msg=E1101
            query = query.join(['listings2', 'collection']).filter(
                    Collection.statuscode!=STATUS['EOL'])
        pkg_list = []
        statuses = set()
        collectn_map = {}
        for pkg in query:
            pkg.json_props = {'Package':('listings',)}
            pkg_list.append(pkg)
            for pkglisting in pkg.listings:
                statuses.add(pkglisting.statuscode)
                if pkglisting.collection.collectionid not in collectn_map \
                    and pkglisting.collection.statuscode!=STATUS['EOL']:
                    collectn_map[pkglisting.collection.collectionid] = pkglisting.collection.branchname

        statusMap = dict([(statuscode, STATUS[statuscode]) for statuscode in
            statuses])

        return dict(title=page_title, pkgCount=len(pkg_list), pkgs=pkg_list,
                fasname='orphan', eol=eol, statusMap=statusMap,
                collectn_map=collectn_map)
예제 #10
0
    def __getitem__(self, username):
        '''Retrieve a user for a username.

        First read from the cache.  If not in the cache, refresh from the
        server and try again.

        If the user does not exist then, KeyError will be raised.
        '''
        username = username.strip()
        if username not in self:
            if not username:
                # If the key is just whitespace, raise KeyError immediately,
                # don't try to pull from fas
                raise KeyError(username)
            LOG.debug(_('refresh forced for %(user)s') % {'user':  username})
            person = self.fas.person_by_username(username)
            if not person:
                # no value for this username
                raise KeyError(username)
            self[username] = person
        return super(UserCache, self).__getitem__(username)
예제 #11
0
    def index(self, eol=True):
        '''List the Collections we know about.

        :kwarg eol: Default True.  If set to False, only return collections
            which are not eol
        :returns: list of collections
        '''
        #pylint:disable-msg=E1101
        collections = Collection.query.options(lazyload('listings'),
                lazyload('status')).add_column(CollectionPackage.numpkgs
                ).filter(Collection.id==CollectionPackage.id).order_by(
            Collection.name, Collection.version)
        #pylint:enable-msg=E1101
        if not eol:
            collections = collections.filter(Collection.statuscode!=
                    STATUS['EOL'])

        status_map = dict(((c[0].statuscode, c[0].status.locale['C'].statusname) for
            c in collections))

        return dict(title=_('%(app)s -- Collection Overview') %
                {'app': self.app_title}, collections=collections,
                status_map=status_map)
예제 #12
0
    def mass_branch(self, branch):
        '''Mass branch all packages listed as non-blocked in koji to the pkgdb.

        Note: At some point, this will need to do the reverse: we'll maintain
        the list of dead packages in the pkgdb and sync that information to
        koji.

        Note: It is safe to call this method repeatedly.  If all packages have
        been branched already, new invokations will have no effect.

        :arg branch: Name of the branch to branch all packages for
        :returns: number of packages branched
        :raises InvalidBranch: If the branch does not exist in the pkgdb or
            koji
        :raises ServiceError: If we cannot log into koji
        :raises CannotClone: If some branches could not be cloned.  This will
            also return the names of the uncloned packages in the `unbranched`
            variable.
        '''
        # Retrieve configuration values
        koji_url = config.get('koji.huburl',
                'https://koji.fedoraproject.org/kojihub')
        pkgdb_cert = config.get('cert.user', '/etc/pki/pkgdb/pkgdb.pem')
        user_ca = config.get('cert.user_ca',
                '/etc/pki/pkgdb/fedora-server-ca.cert')
        server_ca = config.get('cert.server_ca',
                '/etc/pki/pkgdb/fedora-upload-ca.cert')

        # Retrieve the collection to make the new branches on
        try:
            #pylint:disable-msg=E1101
            to_branch = Branch.query.filter_by(branchname=branch).one()
        except InvalidRequestError, e:
            session.rollback() #pylint:disable-msg=E1101
            flash(_('Unable to locate a branch for %(branch)s') % {
                'branch': branch})
            return dict(exc='InvalidBranch')
예제 #13
0
    def vcs(self):
        '''Return ACLs for the version control system.

        The format of the returned data is this:
        packageAcls['pkg']['branch']['acl'].'type' = (list of users/groups)
        For instance:
          packageAcls['bzr']['FC-6']['commit'].group = (cvsextras,)
          packageAcls['bzr']['FC-6']['commit'].people = (shahms, toshio)

        This method can display a long list of users but most people will want
        to access it as JSON data with the ?tg_format=json query parameter.
        '''
        # Store our acls in a dict
        package_acls = {}

        # Get the vcs group acls from the db

        group_acls = select((
            #pylint:disable-msg=E1101
            Package.name,
            Branch.branchname,
            GroupPackageListing.groupname), and_(
                GroupPackageListingAcl.acl == 'commit',
                GroupPackageListingAcl.statuscode == STATUS['Approved'],
                GroupPackageListingAcl.grouppackagelistingid \
                        == GroupPackageListing.id,
                GroupPackageListing.packagelistingid \
                        == PackageListing.id,
                PackageListing.packageid == Package.id,
                PackageListing.collectionid == Collection.id,
                Branch.collectionid == Collection.id,
                PackageListing.statuscode != STATUS['Removed'],
                Package.statuscode != STATUS['Removed']
                )
            )

        groups = {}

        # Save them into a python data structure
        for record in group_acls.execute():
            if not record[2] in groups:
                groups[record[2]] = record[2]
            self._add_to_vcs_acl_list(package_acls, 'commit',
                    record[0], record[1],
                    groups[record[2]], group=True)
        del group_acls

        # Get the package owners from the db
        # Exclude the orphan user from that.
        owner_acls = select((
            #pylint:disable-msg=E1101
            Package.name,
            Branch.branchname, PackageListing.owner),
            and_(
                PackageListing.packageid==Package.id,
                PackageListing.collectionid==Collection.id,
                PackageListing.owner!='orphan',
                Collection.id==Branch.collectionid,
                PackageListing.statuscode != STATUS['Removed'],
                Package.statuscode != STATUS['Removed']
                ),
            order_by=(PackageListing.owner,)
            )

        # Save them into a python data structure
        for record in owner_acls.execute():
            username = record[2]
            self._add_to_vcs_acl_list(package_acls, 'commit',
                    record[0], record[1],
                    username, group=False)
        del owner_acls

        # Get the vcs user acls from the db
        person_acls = select((
            #pylint:disable-msg=E1101
            Package.name,
            Branch.branchname, PersonPackageListing.username),
            and_(
                PersonPackageListingAcl.acl=='commit',
                PersonPackageListingAcl.statuscode == STATUS['Approved'],
                PersonPackageListingAcl.personpackagelistingid \
                        == PersonPackageListing.id,
                PersonPackageListing.packagelistingid \
                        == PackageListing.id,
                PackageListing.packageid == Package.id,
                PackageListing.collectionid == Collection.id,
                Branch.collectionid == Collection.id,
                PackageListing.statuscode != STATUS['Removed'],
                Package.statuscode != STATUS['Removed']
                ),
            order_by=(PersonPackageListing.username,)
            )
        # Save them into a python data structure
        for record in person_acls.execute():
            username = record[2]
            self._add_to_vcs_acl_list(package_acls, 'commit',
                    record[0], record[1],
                    username, group=False)

        return dict(title=_('%(app)s -- VCS ACLs') % {'app': self.app_title},
                packageAcls=package_acls)
예제 #14
0
    def notify(self, name=None, version=None, eol=False):
        '''List of usernames that should be notified of changes to a package.

        For the collections specified we want to retrieve all of the owners,
        watchbugzilla, and watchcommits accounts.

        :kwarg name: Set to a collection name to filter the results for that
        :kwarg version: Set to a collection version to further filter results
            for a single version
        :kwarg eol: Set to True if you want to include end of life
            distributions
        '''
        # Check for validation errors requesting this form
        errors = jsonify_validation_errors()
        if errors:
            return errors

        # Retrieve Packages, owners, and people on watch* acls
        #pylint:disable-msg=E1101
        owner_query = select(
            (Package.name, PackageListing.owner),
            from_obj=(PackageTable.join(PackageListingTable).join(
                CollectionTable))).where(
                    and_(Package.statuscode == STATUS['Approved'],
                         PackageListing.statuscode ==
                         STATUS['Approved'])).distinct().order_by('name')
        watcher_query = select(
            (Package.name, PersonPackageListing.username),
            from_obj=(PackageTable.join(PackageListingTable).join(
                CollectionTable).join(PersonPackageListingTable).join(
                    PersonPackageListingAclTable))).where(
                        and_(
                            Package.statuscode == STATUS['Approved'],
                            PackageListing.statuscode == STATUS['Approved'],
                            PersonPackageListingAcl.acl.in_(
                                ('watchbugzilla', 'watchcommits')),
                            PersonPackageListingAcl.statuscode ==
                            STATUS['Approved'])).distinct().order_by('name')
        #pylint:enable-msg=E1101

        if not eol:
            # Filter out eol distributions
            #pylint:disable-msg=E1101
            owner_query = owner_query.where(
                CollectionTable.c.statuscode.in_(
                    (STATUS['Active'], STATUS['Under Development'])))
            watcher_query = watcher_query.where(CollectionTable.c.statuscode.\
                                          in_((STATUS['Active'],
                                               STATUS['Under Development'])))
            #pylint:enable-msg=E1101

        # Only grab from certain collections
        if name:
            #pylint:disable-msg=E1101
            owner_query = owner_query.where(CollectionTable.c.name == name)
            watcher_query = watcher_query.where(CollectionTable.c.name == name)
            #pylint:enable-msg=E1101
            if version:
                # Limit the versions of those collections
                #pylint:disable-msg=E1101
                owner_query = owner_query.where(CollectionTable.c.version==\
                                                version)
                watcher_query = watcher_query.where(CollectionTable.c.version\
                                                    ==version)
                #pylint:enable-msg=E1101

        pkgs = {}
        # turn the query into a python object
        for pkg in itertools.chain(owner_query.execute(),
                                   watcher_query.execute()):
            additions = []
            additions.append(pkg[1])
            pkgs.setdefault(pkg[0], set()).update((pkg[1], ))

        # Retrieve list of collection information for generating the
        # collection form
        #pylint:disable-msg=E1101
        collection_list = Collection.query.order_by('name').order_by('version')
        #pylint:enable-msg=E1101
        collections = {}
        for collection in collection_list:
            try:
                collections[collection.name].append(collection.version)
            except KeyError:
                collections[collection.name] = [collection.version]

        # Return the data
        return dict(title=_('%(app)s -- Notification List') %
                    {'app': self.app_title},
                    packages=pkgs,
                    collections=collections,
                    name=name,
                    version=version,
                    eol=eol)
예제 #15
0
"""
Information about this pkgdb release
"""
from pkgdb import _

VERSION = "0.6.0"
NAME = "fedora-packagedb"
DESCRIPTION = _("The Fedora Package Database")
LONG_DESCRIPTION = _(
    """
Keep track of owner, maintainer, and parties interested in the development of
a particular software package within Fedora.  This database is a central store
for important package information and allows querying of the package
information from other tools.
"""
)
AUTHOR = "Toshio Kuratomi"
EMAIL = "*****@*****.**"
COPYRIGHT = "2013 Red Hat, Inc."
URL = "https://fedorahosted.org/packagedb"
DOWNLOAD_URL = "https://fedorahosted.org/releases/p/a/packagedb/"
LICENSE = "GPLv2+"
예제 #16
0
 def login(self, forward_url=None, *args, **kwargs):
     login_dict = f_ctrlers.login(forward_url=forward_url, *args, **kwargs)
     login_dict['title'] = _('Login to the PackageDB')
     return login_dict
예제 #17
0
    def index(self):
        '''Return a  set of statistics about package ownership.
        '''
        # SQLAlchemy monkey patches the table fields into the mapper classes.
        # So we have to disable this check for any statements which use those
        # attributes on mapper classes (E1101)
        # pylint: disable-msg=E1101
        if identity.current.anonymous:
            own = _('need to be logged in')
        else:
            # SQLAlchemy mapped classes are monkey patched
            # pylint: disable-msg=E1101
            own = PackageListing.query.filter(and_(
                PackageListing.owner==identity.current.user_name,
                PackageListing.statuscode==3,
                PackageListing.collectionid==DEVEL)).count()

        # most packages owned in DEVEL collection
        top_owners_select = select(
                [func.count(PackageListing.owner).label('numpkgs'),
                    PackageListing.owner], and_(
                        PackageListing.collectionid==DEVEL,
                        PackageListing.owner!='orphan')).group_by(
                                PackageListing.owner).order_by(
                                        desc('numpkgs')).limit(20)
        top_owners_selection = top_owners_select.execute().fetchall()
        top_owners_names = []
        for listing in top_owners_selection:
            top_owners_names.append(listing.owner)

        # most packages owned or comaintained in DEVEL collection
        maintain_select = select(
                [func.count(PersonPackageListing.username).label('numpkgs'),
                PersonPackageListing.username,
                PackageListing.collectionid],
            and_(
                PersonPackageListing.packagelistingid==PackageListing.id,
                PackageListing.collectionid==DEVEL)
            ).group_by(
                PersonPackageListing.username,
                PackageListing.collectionid
            ).order_by(
                desc('numpkgs')
            ).limit(20)
        maintain_names = []
        maintain_selection = maintain_select.execute().fetchall()
        for listing in maintain_selection:
            maintain_names.append(listing.username)

        # total number of packages in pkgdb
        total = PackageListing.query.count()
        # number of packages with no comaintainers
        no_comaintainers = select(
                [PackageListing.id],
            and_(
                PackageListing.id==PersonPackageListing.packagelistingid,
                PackageListing.collectionid==DEVEL,
                PersonPackageListingAcl.
                personpackagelistingid==PersonPackageListing.id,
            not_(
                or_(
                    PersonPackageListingAcl.acl=='commit',
                    PersonPackageListingAcl.acl=='approveacls')
                )
            )).group_by(
                PackageListing.id
            ).execute().rowcount
        # orphan packages in DEVEL 
        orphan_devel = PackageListing.query.filter_by(
            statuscode=STATUS['Orphaned'], collectionid=DEVEL).count()
        # orphan packages in fedora 10
        orphan_latest = PackageListing.query.filter_by(
            statuscode=STATUS['Orphaned'], collectionid=19).count()

        return dict(title=_('%(app)s -- Package Stats') % {
            'app': self.app_title},
            total=total,
            no_comaintainers=no_comaintainers,
            orphan_devel=orphan_devel, orphan_latest=orphan_latest,
            own=own,
            top_owners_names=top_owners_names,
            top_owners_list=top_owners_selection,
            maintain_names=maintain_names,
            maintain_list=maintain_selection,
            message='Warning: Do not depend on the json data from this function remaining the same.  It could change, be moved to other functions, or go away at any time.  There is no guaranteed API stability for this function!')
예제 #18
0
 def __setitem__(self, statusname, value):
     raise TypeError(
         _('\'StatusCache\' object does not support item assignment'))
예제 #19
0
    def default(self, package_name, *args, **kwargs):
        """Display a list of Fedora bugs against a given package."""
        # Nasty, nasty hack.  The packagedb, via bugz.fp.o is getting sent
        # requests to download files.  These refused to go away even when
        # we fixed up the apache redirects.  Send them to download.fp.o
        # manually.
        if args or kwargs:
            if args:
                url = (
                    "http://download.fedoraproject.org/"
                    + quote(package_name)
                    + "/"
                    + "/".join([quote(a) for a in args])
                )
            elif kwargs:
                url = (
                    "http://mirrors.fedoraproject.org/"
                    + quote(package_name)
                    + "?"
                    + "&".join([quote(q) + "=" + quote(v) for (q, v) in kwargs.items()])
                )
                LOG.warning(_("Invalid URL: redirecting: %(url)s") % {"url": url})
            raise redirect(url)

        query = {
            "product": ("Fedora", "Fedora EPEL"),
            "component": package_name,
            "bug_status": (
                "ASSIGNED",
                "NEW",
                "MODIFIED",
                "ON_DEV",
                "ON_QA",
                "VERIFIED",
                "FAILS_QA",
                "RELEASE_PENDING",
                "POST",
            ),
        }
        # :E1101: python-bugzilla monkey patches this in
        try:
            bugzilla = get_bz()
        except xmlrpclib.ProtocolError:
            error = dict(
                status=False,
                title=_("%(app)s -- Unable to contact bugzilla") % {"app": self.app_title},
                message=_("Bugzilla is unavailable.  Unable to determine" " bugs for %(pkg)s") % {"pkg": package_name},
            )
            if request_format() != "json":
                error["tg_template"] = "pkgdb.templates.errors"
            return error

        raw_bugs = bugzilla.query(query)  # pylint: disable-msg=E1101
        bugs = BugList(self.bzQueryUrl, self.bzUrl)
        for bug in raw_bugs:
            bugs.append(bug)

        if not bugs:
            # Check that the package exists
            try:
                # pylint: disable-msg=E1101
                Package.query.filter_by(name=package_name).one()
            except InvalidRequestError:
                error = dict(
                    status=False,
                    title=_("%(app)s -- Not a Valid Package Name") % {"app": self.app_title},
                    message=_("No such package %(pkg)s") % {"pkg": package_name},
                )
                if request_format() != "json":
                    error["tg_template"] = "pkgdb.templates.errors"
                return error

        return dict(
            title=_("%(app)s -- Open Bugs for %(pkg)s") % {"app": self.app_title, "pkg": package_name},
            package=package_name,
            bugs=bugs,
        )
예제 #20
0
    def default(self, searchwords=''):
        '''Return a list of all packages in the database.

           :kwarg searchwords: optional - string to restrict the list, can use
                * and ? as wildcards
        '''
        sql_searchwords = ''
        if searchwords:
            # Escape special chars and turn shell-style '*' and '?' wildcards
            # into sql '%' and '_' wildcards
            sql_searchwords = searchwords.replace('\\\\', '\\\\\\\\')\
                    .replace('%', '\\%').replace('_', '\\_')\
                    .replace('*', '%').replace('?', '_')

        server_webpath = config.get('server.webpath', '/pkgdb')
        if request.path.startswith("%s/acls/" % server_webpath):
            if request.path.startswith('%s/acls/bugs/' % server_webpath):
                mode = 'acls/bugs/'
                bzUrl = config.get('bugzilla.url',
                                   'https://bugzilla.redhat.com/')
            else:
                mode = 'acls/name/'
                bzUrl = ''
            if sql_searchwords != '':
                if sql_searchwords.isdigit() and int(sql_searchwords) < 10: # 0-9
                    #pylint:disable-msg=E1101
                    packages = Package.query.options(
                            lazyload('listings2'), lazyload('status')
                        ).filter(or_(Package.name.between('0','9'),
                                     Package.name.like('9%')))
                    #pylint:enable-msg=E1101
                else: 
                    #pylint:disable-msg=E1101
                    packages = Package.query.options(
                        lazyload('listings2'),
                        lazyload('status')).filter(
                            Package.name.ilike(sql_searchwords, escape='\\\\')
                            ).order_by(Package.name.asc())
                    #pylint:enable-msg=E1101
            else:
                #pylint:disable-msg=E1101
                packages = Package.query.options(lazyload('listings2'),
                            lazyload('status'))
                #pylint:enable-msg=E1101
            # minus removed packages
            #pylint:disable-msg=E1101
            packages = packages.filter(
                    Package.statuscode!=STATUS['Removed'])
            #pylint:enable-msg=E1101


        # generate the statusMap and collectn_map
        statuses = set()
        collectn_map = {}
        pkg_list = []
        for pkg in packages:
            pkg.json_props = {'Package':('listings',)}
            pkg_list.append(pkg)
            statuses.add(pkg.statuscode)
            for pkglisting in pkg.listings:
                if pkglisting.collection.collectionid not in collectn_map:
                    collectn_map[pkglisting.collection.collectionid] = \
                        pkglisting.collection.branchname
        statusMap = dict([(statuscode, STATUS[statuscode]) for statuscode in statuses])

        return dict(title=_('%(app)s -- Packages Overview %(mode)s') % {
            'app': self.app_title, 'mode': mode.strip('/')},
                       searchwords=searchwords, packages=pkg_list, mode=mode,
                       bzurl=bzUrl, statusMap=statusMap, collectn_map=collectn_map)
예제 #21
0
'''
Information about this pkgdb release
'''
from pkgdb import _

VERSION = '0.6.0'
NAME = 'fedora-packagedb'
DESCRIPTION = _('The Fedora Package Database')
LONG_DESCRIPTION = _('''
Keep track of owner, maintainer, and parties interested in the development of
a particular software package within Fedora.  This database is a central store
for important package information and allows querying of the package
information from other tools.
''')
AUTHOR = 'Toshio Kuratomi'
EMAIL = '*****@*****.**'
COPYRIGHT = '2013 Red Hat, Inc.'
URL = 'https://fedorahosted.org/packagedb'
DOWNLOAD_URL = 'https://fedorahosted.org/releases/p/a/packagedb/'
LICENSE = 'GPLv2+'
예제 #22
0
    def bugzilla(self, collection=None):
        '''Return the package attributes used by bugzilla.

        :karg collection: Name of the bugzilla collection to gather data on.

        Note: The data returned by this function is for the way the current
        Fedora bugzilla is setup as of (2007/6/25).  In the future, bugzilla
        may change to have separate products for each collection-version.
        When that happens we'll have to change what this function returns.

        The returned data looks like this:

        bugzillaAcls[collection][package].attribute
        attribute is one of:
            :owner: FAS username for the owner
            :qacontact: if the package has a special qacontact, their userid
                is listed here
            :summary: Short description of the package
            :cclist: list of FAS userids that are watching the package
        '''
        bugzilla_acls = {}
        username = None

        # select all packages that are in an active release
        #pylint:disable-msg=E1101
        package_info = select((Collection.name, Package.name,
                               PackageListing.owner, PackageListing.qacontact,
                               Package.summary),
                              and_(Collection.id==PackageListing.collectionid,
                                   Package.id==PackageListing.packageid,
                                   Package.statuscode!=STATUS['Removed'],
                                   PackageListing.statuscode!=STATUS['Removed'],
                                   Collection.statuscode.in_((STATUS['Active'],
                                       STATUS['Under Development'])),
                                  ),
                              order_by=(Collection.name,), distinct=True)
        if (collection):
            package_info = package_info.where(Collection.branchname==collection);

        # List of packages that need more processing to decide who the owner
        # should be.
        undupe_owners = []

        for pkg in package_info.execute():
            # Lookup the collection
            collection_name = pkg[0]
            if (collection):
                collection_name += ' (%s)' % collection

            try:
                collections = bugzilla_acls[collection_name]
            except KeyError:
                collections = {}
                bugzilla_acls[collection_name] = collections
            # Then the package
            package_name = pkg[1]
            try:
                package = collections[package_name]
            except KeyError:
                package = BugzillaInfo()
                collections[package_name] = package

            # Save the package information in the data structure to return
            if not package.owner:
                package.owner = pkg[2]
            elif pkg[2] != package.owner:
                # There are multiple owners for this package.
                undupe_owners.append(package_name)
            if pkg[3]:
                package.qacontact = pkg[3]
            package.summary = pkg[4]

        if undupe_owners:
            # These are packages that have different owners in different
            # branches.  Need to find one to be the owner of the bugzilla
            # component
            #pylint:disable-msg=E1101
            package_info = select((Collection.name, Collection.version,
                                   Package.name, PackageListing.owner),
                                  and_(Collection.id==\
                                           PackageListing.collectionid,
                                       Package.id==\
                                           PackageListing.packageid,
                                       Package.statuscode!=STATUS['Removed'],
                                       PackageListing.statuscode!=\
                                           STATUS['Removed'],
                                       Collection.statuscode.\
                                           in_((STATUS['Active'],
                                                STATUS['Under Development'])),
                                       Package.name.in_(undupe_owners),
                                      ),
                                  order_by=(Collection.name,
                                            Collection.version),
                                  distinct=True)

            if (collection):
                package_info = package_info.where(Collection.branchname==\
                                                  collection);
            #pylint:enable-msg=E1101

            # Organize the results so that we have:
            # [packagename][collectionname][collectionversion] = owner
            by_pkg = {}
            for pkg in package_info.execute():
                # Order results by package
                try:
                    package = by_pkg[pkg[2]]
                except KeyError:
                    package = {}
                    by_pkg[pkg[2]] = package

                # Then collection
                if (collection):
                    pkg[0] += ' (%s)' % collection
                try:
                    collections = package[pkg[0]]
                except KeyError:
                    collections = {}
                    package[pkg[0]] = collections

                # Then collection version == owner
                collections[pkg[1]] = pkg[3]

            # Find the proper owner
            for pkg in by_pkg:
                for collection_name in by_pkg[pkg]:
                    if collection_name.startswith('Fedora'):
                        # If devel exists, use its owner
                        # We can safely ignore orphan because we already know
                        # this is a dupe and thus a non-orphan exists.
                        if 'devel' in by_pkg[pkg][collection_name]:
                            if by_pkg[pkg][collection_name]['devel'] == 'orphan'\
                                    and len(by_pkg[pkg][collection_name]) > 1:
                                # If there are other owners, try to use them
                                # instead of orphan
                                del by_pkg[pkg][collection_name]['devel']
                            else:
                                # Prefer devel above all others
                                bugzilla_acls[collection_name][pkg].owner = \
                                        by_pkg[pkg][collection_name]['devel']
                                continue

                    # For any collection except Fedora or Fedora if the devel
                    # version does not exist, treat releases as numbers and
                    # take the results from the latest number
                    releases = [int(r) for r in by_pkg[pkg][collection_name] \
                            if by_pkg[pkg][collection_name][r] != 'orphan']
                    if not releases:
                        # Every release was an orphan
                        bugzilla_acls[collection_name][pkg].owner = 'orphan'
                    else:
                        releases.sort()
                        bugzilla_acls[collection_name][pkg].owner = \
                            by_pkg[pkg][collection_name][unicode(releases[-1])]

        # Retrieve the user acls

        #pylint:disable-msg=E1101
        person_acls = select((Package.name, Collection.name,
                              PersonPackageListing.username),
                             and_(PersonPackageListingAcl.acl==\
                                      'watchbugzilla',
                                  PersonPackageListingAcl.statuscode==\
                                      STATUS['Approved'],
                                  PersonPackageListingAcl.\
                                      personpackagelistingid==\
                                      PersonPackageListing.id,
                                  PersonPackageListing.packagelistingid==\
                                      PackageListing.id,
                                  PackageListing.packageid==Package.id,
                                  PackageListing.collectionid==Collection.id,
                                  Package.statuscode!=STATUS['Removed'],
                                  PackageListing.statuscode!=STATUS['Removed'],
                                  Collection.statuscode.in_((STATUS['Active'],
                                      STATUS['Under Development'])),
                                 ),
                             order_by=(PersonPackageListing.username,),
                             distinct=True
                            )
        if (collection):
            person_acls = person_acls.where(Collection.branchname==collection);

        # Save them into a python data structure
        for record in person_acls.execute():
            username = record[2]
            collection_name = record[1]
            if (collection):
                collection_name += ' (%s)' % collection
            self._add_to_bugzilla_acl_list(bugzilla_acls, record[0], collection_name,
                    username, group=False)

        ### TODO: No group acls at the moment
        # There are no group acls to take advantage of this.
        return dict(title=_('%(app)s -- Bugzilla ACLs') % {
            'app': self.app_title}, bugzillaAcls=bugzilla_acls)
예제 #23
0
    def notify(self, name=None, version=None, eol=False):
        '''List of usernames that should be notified of changes to a package.

        For the collections specified we want to retrieve all of the owners,
        watchbugzilla, and watchcommits accounts.

        :kwarg name: Set to a collection name to filter the results for that
        :kwarg version: Set to a collection version to further filter results
            for a single version
        :kwarg eol: Set to True if you want to include end of life
            distributions
        '''
        # Check for validation errors requesting this form
        errors = jsonify_validation_errors()
        if errors:
            return errors

        # Retrieve Packages, owners, and people on watch* acls
        #pylint:disable-msg=E1101
        owner_query = select((Package.name, PackageListing.owner),
                from_obj=(PackageTable.join(PackageListingTable).join(
                    CollectionTable))).where(and_(
                        Package.statuscode == STATUS['Approved'],
                        PackageListing.statuscode == STATUS['Approved'])
                        ).distinct().order_by('name')
        watcher_query = select((Package.name, PersonPackageListing.username),
                from_obj=(PackageTable.join(PackageListingTable).join(
                    CollectionTable).join(PersonPackageListingTable).join(
                        PersonPackageListingAclTable))).where(and_(
                            Package.statuscode == STATUS['Approved'],
                            PackageListing.statuscode == STATUS['Approved'],
                            PersonPackageListingAcl.acl.in_(
                                ('watchbugzilla', 'watchcommits')),
                            PersonPackageListingAcl.statuscode ==
                                STATUS['Approved']
                        )).distinct().order_by('name')
        #pylint:enable-msg=E1101

        if not eol:
            # Filter out eol distributions
            #pylint:disable-msg=E1101
            owner_query = owner_query.where(CollectionTable.c.statuscode.in_(
                (STATUS['Active'], STATUS['Under Development'])))
            watcher_query = watcher_query.where(CollectionTable.c.statuscode.\
                                          in_((STATUS['Active'],
                                               STATUS['Under Development'])))
            #pylint:enable-msg=E1101

        # Only grab from certain collections
        if name:
            #pylint:disable-msg=E1101
            owner_query = owner_query.where(CollectionTable.c.name==name)
            watcher_query = watcher_query.where(CollectionTable.c.name==name)
            #pylint:enable-msg=E1101
            if version:
                # Limit the versions of those collections
                #pylint:disable-msg=E1101
                owner_query = owner_query.where(CollectionTable.c.version==\
                                                version)
                watcher_query = watcher_query.where(CollectionTable.c.version\
                                                    ==version)
                #pylint:enable-msg=E1101

        pkgs = {}
        # turn the query into a python object
        for pkg in itertools.chain(owner_query.execute(),
                watcher_query.execute()):
            additions = []
            additions.append(pkg[1])
            pkgs.setdefault(pkg[0], set()).update((pkg[1],))

        # Retrieve list of collection information for generating the
        # collection form
        #pylint:disable-msg=E1101
        collection_list = Collection.query.order_by('name').order_by('version')
        #pylint:enable-msg=E1101
        collections = {}
        for collection in collection_list:
            try:
                collections[collection.name].append(collection.version)
            except KeyError:
                collections[collection.name] = [collection.version]

        # Return the data
        return dict(title=_('%(app)s -- Notification List') % {
            'app': self.app_title}, packages=pkgs, collections=collections,
            name=name, version=version, eol=eol)
예제 #24
0
    def bugzilla(self, collection=None):
        '''Return the package attributes used by bugzilla.

        :karg collection: Name of the bugzilla collection to gather data on.

        Note: The data returned by this function is for the way the current
        Fedora bugzilla is setup as of (2007/6/25).  In the future, bugzilla
        may change to have separate products for each collection-version.
        When that happens we'll have to change what this function returns.

        The returned data looks like this:

        bugzillaAcls[collection][package].attribute
        attribute is one of:
            :owner: FAS username for the owner
            :qacontact: if the package has a special qacontact, their userid
                is listed here
            :summary: Short description of the package
            :cclist: list of FAS userids that are watching the package
        '''
        bugzilla_acls = {}
        username = None

        # select all packages that are in an active release
        #pylint:disable-msg=E1101
        package_info = select(
            (Collection.name, Package.name, PackageListing.owner,
             PackageListing.qacontact, Package.summary),
            and_(
                Collection.id == PackageListing.collectionid,
                Package.id == PackageListing.packageid,
                Package.statuscode != STATUS['Removed'],
                PackageListing.statuscode != STATUS['Removed'],
                Collection.statuscode.in_(
                    (STATUS['Active'], STATUS['Under Development'])),
            ),
            order_by=(Collection.name, ),
            distinct=True)
        if (collection):
            package_info = package_info.where(
                Collection.branchname == collection)

        # List of packages that need more processing to decide who the owner
        # should be.
        undupe_owners = []

        for pkg in package_info.execute():
            # Lookup the collection
            collection_name = pkg[0]
            if (collection):
                collection_name += ' (%s)' % collection

            try:
                collections = bugzilla_acls[collection_name]
            except KeyError:
                collections = {}
                bugzilla_acls[collection_name] = collections
            # Then the package
            package_name = pkg[1]
            try:
                package = collections[package_name]
            except KeyError:
                package = BugzillaInfo()
                collections[package_name] = package

            # Save the package information in the data structure to return
            if not package.owner:
                package.owner = pkg[2]
            elif pkg[2] != package.owner:
                # There are multiple owners for this package.
                undupe_owners.append(package_name)
            if pkg[3]:
                package.qacontact = pkg[3]
            package.summary = pkg[4]

        if undupe_owners:
            # These are packages that have different owners in different
            # branches.  Need to find one to be the owner of the bugzilla
            # component
            #pylint:disable-msg=E1101
            package_info = select((Collection.name, Collection.version,
                                   Package.name, PackageListing.owner),
                                  and_(Collection.id==\
                                           PackageListing.collectionid,
                                       Package.id==\
                                           PackageListing.packageid,
                                       Package.statuscode!=STATUS['Removed'],
                                       PackageListing.statuscode!=\
                                           STATUS['Removed'],
                                       Collection.statuscode.\
                                           in_((STATUS['Active'],
                                                STATUS['Under Development'])),
                                       Package.name.in_(undupe_owners),
                                      ),
                                  order_by=(Collection.name,
                                            Collection.version),
                                  distinct=True)

            if (collection):
                package_info = package_info.where(Collection.branchname==\
                                                  collection)
            #pylint:enable-msg=E1101

            # Organize the results so that we have:
            # [packagename][collectionname][collectionversion] = owner
            by_pkg = {}
            for pkg in package_info.execute():
                # Order results by package
                try:
                    package = by_pkg[pkg[2]]
                except KeyError:
                    package = {}
                    by_pkg[pkg[2]] = package

                # Then collection
                if (collection):
                    pkg[0] += ' (%s)' % collection
                try:
                    collections = package[pkg[0]]
                except KeyError:
                    collections = {}
                    package[pkg[0]] = collections

                # Then collection version == owner
                collections[pkg[1]] = pkg[3]

            # Find the proper owner
            for pkg in by_pkg:
                for collection_name in by_pkg[pkg]:
                    if collection_name.startswith('Fedora'):
                        # If devel exists, use its owner
                        # We can safely ignore orphan because we already know
                        # this is a dupe and thus a non-orphan exists.
                        if 'devel' in by_pkg[pkg][collection_name]:
                            if by_pkg[pkg][collection_name]['devel'] == 'orphan'\
                                    and len(by_pkg[pkg][collection_name]) > 1:
                                # If there are other owners, try to use them
                                # instead of orphan
                                del by_pkg[pkg][collection_name]['devel']
                            else:
                                # Prefer devel above all others
                                bugzilla_acls[collection_name][pkg].owner = \
                                        by_pkg[pkg][collection_name]['devel']
                                continue

                    # For any collection except Fedora or Fedora if the devel
                    # version does not exist, treat releases as numbers and
                    # take the results from the latest number
                    releases = [int(r) for r in by_pkg[pkg][collection_name] \
                            if by_pkg[pkg][collection_name][r] != 'orphan']
                    if not releases:
                        # Every release was an orphan
                        bugzilla_acls[collection_name][pkg].owner = 'orphan'
                    else:
                        releases.sort()
                        bugzilla_acls[collection_name][pkg].owner = \
                            by_pkg[pkg][collection_name][unicode(releases[-1])]

        # Retrieve the user acls

        #pylint:disable-msg=E1101
        person_acls = select((Package.name, Collection.name,
                              PersonPackageListing.username),
                             and_(PersonPackageListingAcl.acl==\
                                      'watchbugzilla',
                                  PersonPackageListingAcl.statuscode==\
                                      STATUS['Approved'],
                                  PersonPackageListingAcl.\
                                      personpackagelistingid==\
                                      PersonPackageListing.id,
                                  PersonPackageListing.packagelistingid==\
                                      PackageListing.id,
                                  PackageListing.packageid==Package.id,
                                  PackageListing.collectionid==Collection.id,
                                  Package.statuscode!=STATUS['Removed'],
                                  PackageListing.statuscode!=STATUS['Removed'],
                                  Collection.statuscode.in_((STATUS['Active'],
                                      STATUS['Under Development'])),
                                 ),
                             order_by=(PersonPackageListing.username,),
                             distinct=True
                            )
        if (collection):
            person_acls = person_acls.where(
                Collection.branchname == collection)

        # Save them into a python data structure
        for record in person_acls.execute():
            username = record[2]
            collection_name = record[1]
            if (collection):
                collection_name += ' (%s)' % collection
            self._add_to_bugzilla_acl_list(bugzilla_acls,
                                           record[0],
                                           collection_name,
                                           username,
                                           group=False)

        ### TODO: No group acls at the moment
        # There are no group acls to take advantage of this.
        return dict(title=_('%(app)s -- Bugzilla ACLs') %
                    {'app': self.app_title},
                    bugzillaAcls=bugzilla_acls)
예제 #25
0
 def __setitem__(self, statusname, value):
     raise TypeError(_('\'StatusCache\' object does not support item assignment'))
예제 #26
0
    def name(self,
             packageName,
             collectionName=None,
             collectionVersion=None,
             eol=False):
        '''Retrieve Packages by their name.

        This method returns ownership and acl information about a package.
        When given optional arguments the information can be limited by what
        collections they are present in.

        :arg packageName: Name of the package to lookup
        :kwarg collectionName: If given, limit information to branches for
            this distribution.
        :kwarg collectionVersion: If given, limit information to this
            particular version of a distribution.  Has no effect if
            collectionName is not also specified.
        :kwarg eol: end-of-life flag.  If True, do not limit information.
            If False, limit information to non-eol collections.
        '''

        #pylint:disable-msg=E1101
        # Return the information about a package.
        package = Package.query.filter(
            Package.statuscode != STATUS['Removed']).filter_by(
                name=packageName).first()
        #pylint:enable-msg=E1101
        if not package:
            error = dict(
                status=False,
                title=_('%(app)s -- Invalid Package Name') %
                {'app': self.app_title},
                message=_('The packagename you were linked to'
                          ' (%(pkg)s) does not appear in the Package Database.'
                          ' If you received this error from a link on the'
                          ' fedoraproject.org website, please report it.') %
                {'pkg': packageName})
            if request_format() != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
            return error

        collection = None
        if collectionName:
            #pylint:disable-msg=E1101
            collection = Collection.query.filter_by(name=collectionName)
            #pylint:enable-msg=E1101
            if collectionVersion:
                collection = collection.filter_by(version=collectionVersion)
            if (not eol):
                collection = collection.filter(
                    Collection.statuscode != STATUS['EOL'])
            if not collection.count():
                error = dict(
                    status=False,
                    title=_('%(app)s -- Not a Collection') %
                    {'app': self.app_title},
                    message=_('%(name)s %(ver)s is not a Collection.') % {
                        'name': collectionName,
                        'ver': collectionVersion or ''
                    })
                if request_format() != 'json':
                    error['tg_template'] = 'pkgdb.templates.errors'
                return error

        # Possible ACLs
        acl_names = ('watchbugzilla', 'watchcommits', 'commit', 'approveacls')
        # Possible statuses for acls:
        acl_status = PackageAclStatus.query.options(  #pylint:disable-msg=E1101
            eagerload('locale')).all()
        acl_status_translations = ['']
        for status in acl_status:
            ### FIXME: At some point, we have to pull other translations out,
            # not just C
            if acl_status_translations != 'Obsolete':
                acl_status_translations.append(status.locale['C'].statusname)

        #pylint:disable-msg=E1101
        # Fetch information about all the packageListings for this package
        # The order is a bit complex.  We want:
        # 1) EOL collections last
        # 2) Within those groups, same named collections together
        # 3) Within collections, version devel first,
        # 4) All other collections sorted as numbers in descending order
        pkg_listings = PackageListing.query.options(
                eagerload('people2.acls2.status.locale'),
                eagerload('groups2.acls2.status.locale'),
                eagerload('status.locale'),
                eagerload('collection.status.locale'),)\
                        .filter(PackageListingTable.c.packageid==package.id)\
                        .join(Collection)\
                        .order_by(case(value=Collection.statuscode,
                                whens={STATUS['EOL']: 999999},
                                else_=0),
                            Collection.name,
                            case(value=Collection.version,
                                whens={'devel':999999},
                                else_=cast(Collection.version, Integer))\
                            .desc()
                        )
        #pylint:enable-msg=E1101
        if collection:
            # User asked to limit it to specific collections
            pkg_listings = pkg_listings.filter(
                PackageListingTable.c.collectionid.in_(
                    [c.id for c in collection]))
            if not pkg_listings.count():
                error = dict(
                    status=False,
                    title=_('%(app)s -- Not in Collection') %
                    {'app': self.app_title},
                    message=_('The package %(pkg)s is not in Collection'
                              ' %(collctn_name)s %(collctn_ver)s.') % {
                                  'pkg': packageName,
                                  'collctn_name': collectionName,
                                  'collctn_ver': collectionVersion or ''
                              })
                if request_format() != 'json':
                    error['tg_template'] = 'pkgdb.templates.errors'
                return error

        # Map of statuscode to statusnames used in this package
        status_map = {}

        if (not eol):
            pkg_listings = pkg_listings.filter(
                Collection.statuscode != STATUS['EOL'])

        pkg_listings = pkg_listings.order_by().all()

        for pkg in pkg_listings:
            pkg.json_props = {
                'PackageListing': ('package', 'collection', 'people', 'groups',
                                   'qacontact', 'owner'),
                'PersonPackageListing': ('aclOrder', ),
                'GroupPackageListing': ('aclOrder', ),
            }

            status_map[pkg.statuscode] = pkg.status.locale['C'].statusname
            status_map[pkg.collection.statuscode] = \
                    pkg.collection.status.locale['C'].statusname

            for person in pkg.people:
                # Setup acls to be accessible via aclName
                person.aclOrder = {}
                for acl in acl_names:
                    person.aclOrder[acl] = None
                for acl in person.acls:
                    statusname = acl.status.locale['C'].statusname
                    status_map[acl.statuscode] = statusname
                    if statusname != 'Obsolete':
                        person.aclOrder[acl.acl] = acl

            for group in pkg.groups:
                # Setup acls to be accessible via aclName
                group.aclOrder = {}
                for acl in acl_names:
                    group.aclOrder[acl] = None
                for acl in group.acls:
                    status_map[acl.statuscode] = \
                            acl.status.locale['C'].statusname
                    group.aclOrder[acl.acl] = acl

        status_map[pkg_listings[0].package.statuscode] = \
                pkg_listings[0].package.status.locale['C'].statusname

        return dict(title=_('%(title)s -- %(pkg)s') % {
            'title': self.app_title,
            'pkg': package.name
        },
                    packageListings=pkg_listings,
                    statusMap=status_map,
                    aclNames=acl_names,
                    aclStatus=acl_status_translations)
예제 #27
0
        server_ca = config.get('cert.server_ca',
                '/etc/pki/pkgdb/fedora-upload-ca.cert')

        # Retrieve the collection to make the new branches on
        try:
            #pylint:disable-msg=E1101
            to_branch = Branch.query.filter_by(branchname=branch).one()
        except InvalidRequestError, e:
            session.rollback() #pylint:disable-msg=E1101
            flash(_('Unable to locate a branch for %(branch)s') % {
                'branch': branch})
            return dict(exc='InvalidBranch')

        if to_branch.statuscode == STATUS['EOL']:
            session.rollback() #pylint:disable-msg=E1101
            flash(_('Will not branch packages in EOL collection %(branch)s') % {
                'branch': branch})
            return dict(exc='InvalidBranch')

        # Retrieve a koji session to get the list of packages from
        koji_name = to_branch.koji_name
        if not koji_name:
            session.rollback() #pylint:disable-msg=E1101
            flash(_('Unable to mass branch for %(branch)s because it is not'
                ' managed by koji') % {'branch': branch})
            return dict(exc='InvalidBranch')

        koji_session = koji.ClientSession(koji_url)
        if not koji_session.ssl_login(cert=pkgdb_cert, ca=user_ca,
                serverca=server_ca):
            session.rollback() #pylint:disable-msg=E1101
예제 #28
0
    def default(self, package_name, *args, **kwargs):
        '''Display a list of Fedora bugs against a given package.'''
        # Nasty, nasty hack.  The packagedb, via bugz.fp.o is getting sent
        # requests to download files.  These refused to go away even when
        # we fixed up the apache redirects.  Send them to download.fp.o
        # manually.
        if args or kwargs:
            if args:
                url = 'http://download.fedoraproject.org/' \
                        + quote(package_name) \
                        + '/' + '/'.join([quote(a) for a in args])
            elif kwargs:
                url = 'http://mirrors.fedoraproject.org/' \
                        + quote(package_name) \
                        + '?' + '&'.join([quote(q) + '=' + quote(v) for (q, v)
                            in kwargs.items()])
                LOG.warning(
                    _('Invalid URL: redirecting: %(url)s') % {'url': url})
            raise redirect(url)

        query = {
            'product': ('Fedora', 'Fedora EPEL'),
            'component':
            package_name,
            'bug_status': ('ASSIGNED', 'NEW', 'MODIFIED', 'ON_DEV', 'ON_QA',
                           'VERIFIED', 'FAILS_QA', 'RELEASE_PENDING', 'POST')
        }
        # :E1101: python-bugzilla monkey patches this in
        try:
            bugzilla = get_bz()
        except xmlrpclib.ProtocolError:
            error = dict(
                status=False,
                title=_('%(app)s -- Unable to contact bugzilla') %
                {'app': self.app_title},
                message=_('Bugzilla is unavailable.  Unable to determine'
                          ' bugs for %(pkg)s') % {'pkg': package_name})
            if request_format() != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
            return error

        raw_bugs = bugzilla.query(query)  # pylint: disable-msg=E1101
        bugs = BugList(self.bzQueryUrl, self.bzUrl)
        for bug in raw_bugs:
            bugs.append(bug)

        if not bugs:
            # Check that the package exists
            try:
                # pylint: disable-msg=E1101
                Package.query.filter_by(name=package_name).one()
            except InvalidRequestError:
                error = dict(status=False,
                             title=_('%(app)s -- Not a Valid Package Name') %
                             {'app': self.app_title},
                             message=_('No such package %(pkg)s') %
                             {'pkg': package_name})
                if request_format() != 'json':
                    error['tg_template'] = 'pkgdb.templates.errors'
                return error

        return dict(title=_('%(app)s -- Open Bugs for %(pkg)s') % {
            'app': self.app_title,
            'pkg': package_name
        },
                    package=package_name,
                    bugs=bugs)
예제 #29
0
    def packages(self, fasname=None, acls=None, eol=None):
        '''List packages that the user is interested in.

        This method returns a list of packages owned by the user in current,
        non-EOL distributions.  The user has the ability to filter this to
        provide more or less information by adding query params for acls and
        EOL.

        :kwarg fasname: The name of the user to get the package list for.
                  Default: The logged in user.
        :kwarg acls: List of acls to select.
               Note: for backwards compatibility, this can also be a comma
               separated string of acls.
               Default: all acls.
        :kwarg eol: If set, list packages that are in EOL distros.
        :returns: A list of packages.
        '''
        # Set EOL to false for a few obvious values
        if not eol or eol.lower() in ('false', 'f', '0'):
            eol = False
        else:
            eol = bool(eol)

        # For backward compat, redirect the orphan user to the orphan page
        if fasname == 'orphan':
            params = {}
            if eol:
                params['eol'] = True
            if request_format() == 'json':
                params['tg_format'] = 'json'
            url = '/acls/orphans'
            if params:
                url = url + '?' + urllib.urlencode(params, True)

            raise redirect(url)

        if not acls:
            # Default to all acls
            acls = [k[0] for k in self.allAcls]
        elif isinstance(acls, basestring):
            # For backwards compatibility, make acls into a list if it's a
            # comma separated string of values
            acls = acls.split(',')

        # Create a list where store acl name, whether the acl is currently
        # being filtered for, and the label to use to display the acl.
        acl_list = [(a[0], a[0] in acls, a[1]) for a in self.allAcls]

        # Have to either get fasname from the URL or current user
        if fasname == None:
            if identity.current.anonymous:
                raise identity.IdentityFailure(
                        _('You must be logged in to view your information'))
            else:
                fasname = identity.current.user_name

        page_title = _('%(app)s -- %(name)s -- Packages') % {
                'app': self.app_title, 'name': fasname}

        # pylint: disable-msg=E1101
        query = Package.query.join('listings2').distinct().options(
                lazyload('listings2.groups2'), 
                lazyload('listings2.groups2.acls2'),
                lazyload('listings2.people2'), 
                lazyload('listings2.people2.acls2'), lazyload('listings2'))

        if not eol:
            # We don't want EOL releases, filter those out of each clause
            query = query.join(['listings2', 'collection']).filter(
                        Collection.statuscode != STATUS['EOL'])

        queries = []
        if 'owner' in acls:
            # Return any package for which the user is the owner
            queries.append(query.filter(sqlalchemy.and_(
                        Package.statuscode.in_((
                            STATUS['Approved'],
                            STATUS['Awaiting Review'],
                            STATUS['Under Review'])),
                        PackageListing.owner==fasname,
                        PackageListing.statuscode.in_((
                            STATUS['Approved'],
                            STATUS['Awaiting Branch'],
                            STATUS['Awaiting Review']))
                        )))
            del acls[acls.index('owner')]

        if acls:
            # Return any package on which the user has an Approved acl.
            queries.append(query.join(['listings2', 'people2']).join(
                    ['listings2', 'people2', 'acls2']).filter(sqlalchemy.and_(
                    Package.statuscode.in_((STATUS['Approved'],
                        STATUS['Awaiting Review'], STATUS['Under Review'])),
                    PersonPackageListing.username == fasname,
                    PersonPackageListingAcl.statuscode == STATUS['Approved'],
                    PackageListing.statuscode.in_((STATUS['Approved'],
                        STATUS['Awaiting Branch'], STATUS['Awaiting Review']))
                    )))
            # Return only those acls which the user wants listed
            queries[-1] = queries[-1].filter(
                    PersonPackageListingAcl.acl.in_(acls))

        if len(queries) == 2:
            my_pkgs = Package.query.select_from(
                            sqlalchemy.union(
                                    queries[0].statement,
                                    queries[1].statement
                                    ))
        else:
            my_pkgs = queries[0]

        my_pkgs = my_pkgs.options(lazyload('listings2.people2'), 
                                  lazyload('listings2.people2.acls2'), 
                                  lazyload('listings2.groups2'), 
                                  lazyload('listings2.groups2.acls2'), 
                                  lazyload('listings2')
                                  ).order_by(Package.name)
        # pylint: enable-msg=E1101
        pkg_list = []
        statuses = set()
        collectn_map = {}
        for pkg in my_pkgs:
            pkg.json_props = {'Package': ('listings',)}
            pkg_list.append(pkg)
            for pkglisting in pkg.listings:
                statuses.add(pkglisting.statuscode)
                if pkglisting.collection.collectionid not in collectn_map \
                    and pkglisting.collection.statuscode!=STATUS['EOL']:
                    collectn_map[pkglisting.collection.collectionid] = pkglisting.collection.branchname

        statusMap = dict([(statuscode, STATUS[statuscode]) for statuscode in
            statuses])

        return dict(title=page_title, pkgCount=len(pkg_list),
                pkgs=pkg_list, acls=acl_list, fasname=fasname, eol=eol,
                statusMap=statusMap, collectn_map=collectn_map)
예제 #30
0
    def id(self, collection_id): #pylint:disable-msg=C0103
        '''Return a page with information on a particular Collection

        :arg collection_id: Numeric id of the collection
        '''
        flash(_('This page is deprecated.  Use %(url)s instead.') %
                {'url': config.get('base_url_filter.base_url',
                    'http://localhost') + tg_url('/collection/name')})
        try:
            collection_id = int(collection_id)
        except ValueError:
            error = dict(status = False,
                    title = _('%(app)s -- Invalid Collection Id') %
                        {'app': self.app_title},
                    message =_('The collection_id you were linked to is not a' \
                            ' valid id.  If you received this error from a' \
                            ' link on the fedoraproject.org website, please' \
                            ' report it.'))
            if request.params.get('tg_format', 'html') != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
            return error

        ### FIXME: Want to return additional info:
        # date it was created (join log table: creation date)
        # The initial import doesn't have this information, though.
        try:
            #pylint:disable-msg=E1101
            collection_entry = Collection.query.options(
                    lazyload('listings2'), eagerload('status.locale'))\
                    .filter_by(id=collection_id).one()
        except InvalidRequestError:
            # Either the id doesn't exist or somehow it references more than
            # one value
            error = dict(status = False,
                    title = _('%(app)s -- Invalid Collection Id') %
                            {'app': self.app_title},
                    message = _('The collection_id you were linked to, %(id)s,'
                            ' does not exist.  If you received this error from'
                            ' a link on the fedoraproject.org website, please'
                            ' report it.') % {'id': collection_id})
            if request.params.get('tg_format', 'html') != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
            return error

        # Why do we reformat the data returned from the database?
        # 1) We don't need all the information in the collection object
        # 2) We need statusname which is not in the specific table.
        collection = {'name': collection_entry.name,
                'version': collection_entry.version,
                'owner': collection_entry.owner,
                'summary': collection_entry.summary,
                'description': collection_entry.description,
                'statusname': collection_entry.status.locale['C'].statusname
                }

        # Retrieve the packagelist for this collection
        # pylint:disable-msg=E1101
        packages = Package.query.options(lazyload('listings2.people2'),
                lazyload('listings2.groups2')).join('listings2')\
                        .filter_by(collectionid=collection_id)\
                        .filter(Package.statuscode!=STATUS['Removed'])
        # pylint:enable-msg=E1101

        return dict(title='%s -- %s %s' % (self.app_title, collection['name'],
            collection['version']), collection=collection, packages=packages)
예제 #31
0
    def name(self, packageName, collectionName=None, collectionVersion=None, eol=False):
        '''Retrieve Packages by their name.

        This method returns ownership and acl information about a package.
        When given optional arguments the information can be limited by what
        collections they are present in.

        :arg packageName: Name of the package to lookup
        :kwarg collectionName: If given, limit information to branches for
            this distribution.
        :kwarg collectionVersion: If given, limit information to this
            particular version of a distribution.  Has no effect if
            collectionName is not also specified.
        :kwarg eol: end-of-life flag.  If True, do not limit information.
            If False, limit information to non-eol collections.
        '''
        
        #pylint:disable-msg=E1101
        # Return the information about a package.
        package = Package.query.filter(
                Package.statuscode!=STATUS['Removed']
                ).filter_by(name=packageName).first()
        #pylint:enable-msg=E1101
        if not package:
            error = dict(status=False,
                    title=_('%(app)s -- Invalid Package Name') % {
                        'app': self.app_title},
                        message=_('The packagename you were linked to'
                        ' (%(pkg)s) does not appear in the Package Database.'
                        ' If you received this error from a link on the'
                        ' fedoraproject.org website, please report it.') % {
                            'pkg': packageName})
            if request_format() != 'json':
                error['tg_template'] = 'pkgdb.templates.errors'
            return error

        collection = None
        if collectionName:
            #pylint:disable-msg=E1101
            collection = Collection.query.filter_by(name=collectionName)
            #pylint:enable-msg=E1101
            if collectionVersion:
                collection = collection.filter_by(version=collectionVersion)
            if (not eol):
                collection = collection.filter(Collection.statuscode!=STATUS['EOL'])
            if not collection.count():
                error = dict(status=False,
                        title=_('%(app)s -- Not a Collection') % {
                            'app': self.app_title},
                        message=_('%(name)s %(ver)s is not a Collection.') % {
                            'name': collectionName,
                            'ver': collectionVersion or ''})
                if request_format() != 'json':
                    error['tg_template'] = 'pkgdb.templates.errors'
                return error

        # Possible ACLs
        acl_names = ('watchbugzilla', 'watchcommits', 'commit', 'approveacls')
        # Possible statuses for acls:
        acl_status = PackageAclStatus.query.options( #pylint:disable-msg=E1101
                eagerload('locale')).all()
        acl_status_translations = ['']
        for status in acl_status:
            ### FIXME: At some point, we have to pull other translations out,
            # not just C
            if acl_status_translations != 'Obsolete':
                acl_status_translations.append(
                        status.locale['C'].statusname)

        #pylint:disable-msg=E1101
        # Fetch information about all the packageListings for this package
        # The order is a bit complex.  We want:
        # 1) EOL collections last
        # 2) Within those groups, same named collections together
        # 3) Within collections, version devel first,
        # 4) All other collections sorted as numbers in descending order
        pkg_listings = PackageListing.query.options(
                eagerload('people2.acls2.status.locale'),
                eagerload('groups2.acls2.status.locale'),
                eagerload('status.locale'),
                eagerload('collection.status.locale'),)\
                        .filter(PackageListingTable.c.packageid==package.id)\
                        .join(Collection)\
                        .order_by(case(value=Collection.statuscode,
                                whens={STATUS['EOL']: 999999},
                                else_=0),
                            Collection.name,
                            case(value=Collection.version,
                                whens={'devel':999999},
                                else_=cast(Collection.version, Integer))\
                            .desc()
                        )
        #pylint:enable-msg=E1101
        if collection:
            # User asked to limit it to specific collections
            pkg_listings = pkg_listings.filter(
                    PackageListingTable.c.collectionid.in_(
                    [c.id for c in collection]))
            if not pkg_listings.count():
                error = dict(status=False,
                        title=_('%(app)s -- Not in Collection') % {
                            'app': self.app_title},
                        message=_('The package %(pkg)s is not in Collection'
                            ' %(collctn_name)s %(collctn_ver)s.') % {
                                'pkg': packageName,
                                'collctn_name': collectionName,
                                'collctn_ver': collectionVersion or ''})
                if request_format() != 'json':
                    error['tg_template'] = 'pkgdb.templates.errors'
                return error

        # Map of statuscode to statusnames used in this package
        status_map = {}

        if (not eol):
            pkg_listings = pkg_listings.filter(Collection.statuscode!=STATUS['EOL'])

        pkg_listings = pkg_listings.order_by().all()

        for pkg in pkg_listings:
            pkg.json_props = {'PackageListing': ('package', 'collection',
                    'people', 'groups', 'qacontact', 'owner'),
                'PersonPackageListing': ('aclOrder', ),
                'GroupPackageListing': ('aclOrder', ),
                }

            status_map[pkg.statuscode] = pkg.status.locale['C'].statusname
            status_map[pkg.collection.statuscode] = \
                    pkg.collection.status.locale['C'].statusname

            for person in pkg.people:
                # Setup acls to be accessible via aclName
                person.aclOrder = {}
                for acl in acl_names:
                    person.aclOrder[acl] = None
                for acl in person.acls:
                    statusname = acl.status.locale['C'].statusname
                    status_map[acl.statuscode] = statusname
                    if statusname != 'Obsolete':
                        person.aclOrder[acl.acl] = acl

            for group in pkg.groups:
                # Setup acls to be accessible via aclName
                group.aclOrder = {}
                for acl in acl_names:
                    group.aclOrder[acl] = None
                for acl in group.acls:
                    status_map[acl.statuscode] = \
                            acl.status.locale['C'].statusname
                    group.aclOrder[acl.acl] = acl

        status_map[pkg_listings[0].package.statuscode] = \
                pkg_listings[0].package.status.locale['C'].statusname

        return dict(title=_('%(title)s -- %(pkg)s') % {
            'title': self.app_title, 'pkg': package.name},
            packageListings=pkg_listings, statusMap = status_map,
            aclNames=acl_names, aclStatus=acl_status_translations)
예제 #32
0
    def vcs(self):
        '''Return ACLs for the version control system.

        The format of the returned data is this:
        packageAcls['pkg']['branch']['acl'].'type' = (list of users/groups)
        For instance:
          packageAcls['bzr']['FC-6']['commit'].group = (cvsextras,)
          packageAcls['bzr']['FC-6']['commit'].people = (shahms, toshio)

        This method can display a long list of users but most people will want
        to access it as JSON data with the ?tg_format=json query parameter.
        '''
        # Store our acls in a dict
        package_acls = {}

        # Get the vcs group acls from the db

        group_acls = select((
            #pylint:disable-msg=E1101
            Package.name,
            Branch.branchname,
            GroupPackageListing.groupname), and_(
                GroupPackageListingAcl.acl == 'commit',
                GroupPackageListingAcl.statuscode == STATUS['Approved'],
                GroupPackageListingAcl.grouppackagelistingid \
                        == GroupPackageListing.id,
                GroupPackageListing.packagelistingid \
                        == PackageListing.id,
                PackageListing.packageid == Package.id,
                PackageListing.collectionid == Collection.id,
                Branch.collectionid == Collection.id,
                PackageListing.statuscode != STATUS['Removed'],
                Package.statuscode != STATUS['Removed']
                )
            )

        groups = {}

        # Save them into a python data structure
        for record in group_acls.execute():
            if not record[2] in groups:
                groups[record[2]] = record[2]
            self._add_to_vcs_acl_list(package_acls,
                                      'commit',
                                      record[0],
                                      record[1],
                                      groups[record[2]],
                                      group=True)
        del group_acls

        # Get the package owners from the db
        # Exclude the orphan user from that.
        owner_acls = select(
            (
                #pylint:disable-msg=E1101
                Package.name,
                Branch.branchname,
                PackageListing.owner),
            and_(PackageListing.packageid == Package.id,
                 PackageListing.collectionid == Collection.id,
                 PackageListing.owner != 'orphan',
                 Collection.id == Branch.collectionid,
                 PackageListing.statuscode != STATUS['Removed'],
                 Package.statuscode != STATUS['Removed']),
            order_by=(PackageListing.owner, ))

        # Save them into a python data structure
        for record in owner_acls.execute():
            username = record[2]
            self._add_to_vcs_acl_list(package_acls,
                                      'commit',
                                      record[0],
                                      record[1],
                                      username,
                                      group=False)
        del owner_acls

        # Get the vcs user acls from the db
        person_acls = select((
            #pylint:disable-msg=E1101
            Package.name,
            Branch.branchname, PersonPackageListing.username),
            and_(
                PersonPackageListingAcl.acl=='commit',
                PersonPackageListingAcl.statuscode == STATUS['Approved'],
                PersonPackageListingAcl.personpackagelistingid \
                        == PersonPackageListing.id,
                PersonPackageListing.packagelistingid \
                        == PackageListing.id,
                PackageListing.packageid == Package.id,
                PackageListing.collectionid == Collection.id,
                Branch.collectionid == Collection.id,
                PackageListing.statuscode != STATUS['Removed'],
                Package.statuscode != STATUS['Removed']
                ),
            order_by=(PersonPackageListing.username,)
            )
        # Save them into a python data structure
        for record in person_acls.execute():
            username = record[2]
            self._add_to_vcs_acl_list(package_acls,
                                      'commit',
                                      record[0],
                                      record[1],
                                      username,
                                      group=False)

        return dict(title=_('%(app)s -- VCS ACLs') % {'app': self.app_title},
                    packageAcls=package_acls)