예제 #1
0
class AdminRepositoryGrid(RepositoryGrid):
    class DeletedColumn(grids.BooleanColumn):
        def get_value(self, trans, grid, repository):
            if repository.deleted:
                return 'yes'
            return ''

    columns = [
        RepositoryGrid.NameColumn(
            "Name",
            key="name",
            link=(lambda item: dict(operation="view_or_manage_repository",
                                    id=item.id)),
            attach_popup=True),
        RepositoryGrid.HeadsColumn("Heads"),
        RepositoryGrid.UserColumn(
            "Owner",
            model_class=model.User,
            link=(lambda item: dict(operation="repositories_by_user",
                                    id=item.id)),
            attach_popup=False,
            key="User.username"),
        RepositoryGrid.DeprecatedColumn("Deprecated",
                                        key="deprecated",
                                        attach_popup=False),
        # Columns that are valid for filtering but are not visible.
        DeletedColumn("Deleted", key="deleted", attach_popup=False)
    ]
    columns.append(
        grids.MulticolFilterColumn("Search repository name",
                                   cols_to_filter=[columns[0]],
                                   key="free-text-search",
                                   visible=False,
                                   filterable="standard"))
    operations = [operation for operation in RepositoryGrid.operations]
    operations.append(
        grids.GridOperation("Delete",
                            allow_multiple=False,
                            condition=(lambda item: not item.deleted),
                            async_compatible=False))
    operations.append(
        grids.GridOperation("Undelete",
                            allow_multiple=False,
                            condition=(lambda item: item.deleted),
                            async_compatible=False))

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.Repository) \
                               .join(model.User.table)
예제 #2
0
class ReviewedRepositoriesIOwnGrid(RepositoriesWithReviewsGrid):
    title = "Reviewed repositories I own"
    columns = [
        RepositoriesWithReviewsGrid.NameColumn("Repository name",
                                               key="name",
                                               link=(lambda item: dict(operation="view_or_manage_repository", id=item.id)),
                                               attach_popup=True),
        RepositoriesWithReviewsGrid.WithReviewsRevisionColumn("Reviewed revisions"),
        RepositoriesWithReviewsGrid.WithoutReviewsRevisionColumn("Revisions for review"),
        RepositoriesWithReviewsGrid.ReviewersColumn("Reviewers", attach_popup=False),
        RepositoryGrid.DeprecatedColumn("Deprecated")
    ]
    columns.append(grids.MulticolFilterColumn("Search repository name",
                                              cols_to_filter=[columns[0]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    operations = [
        grids.GridOperation("Inspect repository revisions",
                            allow_multiple=False,
                            condition=(lambda item: not item.deleted),
                            async_compatible=False)
    ]

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.Repository) \
                               .join((model.RepositoryReview.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id)) \
                               .filter(model.Repository.table.c.user_id == trans.user.id) \
                               .join((model.User.table, model.User.table.c.id == model.RepositoryReview.table.c.user_id)) \
                               .outerjoin((model.ComponentReview.table, model.ComponentReview.table.c.repository_review_id == model.RepositoryReview.table.c.id)) \
                               .outerjoin((model.Component.table, model.Component.table.c.id == model.ComponentReview.table.c.component_id))
예제 #3
0
class RepositoriesWithoutReviewsGrid(RepositoriesWithReviewsGrid):
    # This grid filters out repositories that have been marked as either deprecated or deleted.
    title = "Repositories with no reviews"
    columns = [
        RepositoriesWithReviewsGrid.NameColumn("Repository name",
                                               key="name",
                                               link=(lambda item: dict(operation="view_or_manage_repository", id=item.id)),
                                               attach_popup=True),
        RepositoriesWithReviewsGrid.DescriptionColumn("Synopsis",
                                                      key="description",
                                                      attach_popup=False),
        RepositoriesWithReviewsGrid.WithoutReviewsRevisionColumn("Revisions for review"),
        RepositoriesWithReviewsGrid.UserColumn("Owner",
                                               model_class=model.User,
                                               attach_popup=False,
                                               key="User.username")
    ]
    columns.append(grids.MulticolFilterColumn("Search repository name, description",
                                              cols_to_filter=[columns[0], columns[1]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    operations = [grids.GridOperation("Inspect repository revisions",
                                      allow_multiple=False,
                                      condition=(lambda item: not item.deleted),
                                      async_compatible=False)]

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.Repository) \
                               .filter(and_(model.Repository.table.c.deleted == false(),
                                            model.Repository.table.c.deprecated == false(),
                                            model.Repository.reviews == null())) \
                               .join(model.User.table)
예제 #4
0
class RepositoriesReadyForReviewGrid(RepositoriesWithoutReviewsGrid):
    # Repositories that are ready for human review are those that either:
    # 1) Have no tools
    # 2) Have tools that have been proven to be functionally correct within Galaxy.
    # This grid filters out repositories that have been marked as either deprecated or deleted.
    title = "Repositories ready for review"
    columns = [
        RepositoriesWithoutReviewsGrid.NameColumn(
            "Repository name",
            key="name",
            link=(lambda item: dict(operation="view_or_manage_repository",
                                    id=item.id)),
            attach_popup=True),
        RepositoriesWithoutReviewsGrid.DescriptionColumn("Synopsis",
                                                         key="description",
                                                         attach_popup=False),
        RepositoriesWithoutReviewsGrid.WithoutReviewsRevisionColumn(
            "Revisions for review"),
        RepositoriesWithoutReviewsGrid.UserColumn("Owner",
                                                  model_class=model.User,
                                                  attach_popup=False,
                                                  key="User.username")
    ]
    columns.append(
        grids.MulticolFilterColumn("Search repository name, description",
                                   cols_to_filter=[columns[0], columns[1]],
                                   key="free-text-search",
                                   visible=False,
                                   filterable="standard"))
    operations = [
        grids.GridOperation("Inspect repository revisions",
                            allow_multiple=False,
                            condition=(lambda item: not item.deleted),
                            async_compatible=False)
    ]

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.Repository) \
                               .filter(and_(model.Repository.table.c.deleted == false(),
                                            model.Repository.table.c.deprecated == false(),
                                            model.Repository.reviews == null())) \
                               .join(model.RepositoryMetadata.table) \
                               .filter(and_(model.RepositoryMetadata.table.c.downloadable == true(),
                                            or_(model.RepositoryMetadata.table.c.includes_tools == false(),
                                                and_(model.RepositoryMetadata.table.c.includes_tools == true(),
                                                     model.RepositoryMetadata.table.c.tools_functionally_correct == true())))) \
                               .join(model.User.table)
예제 #5
0
class AdminController(BaseUIController, Admin):

    user_list_grid = admin_grids.UserGrid()
    role_list_grid = admin_grids.RoleGrid()
    group_list_grid = admin_grids.GroupGrid()
    manage_category_grid = admin_grids.ManageCategoryGrid()
    repository_grid = admin_grids.AdminRepositoryGrid()
    repository_metadata_grid = admin_grids.RepositoryMetadataGrid()

    delete_operation = grids.GridOperation(
        "Delete",
        condition=(lambda item: not item.deleted),
        allow_multiple=True)
    undelete_operation = grids.GridOperation(
        "Undelete",
        condition=(lambda item: item.deleted and not item.purged),
        allow_multiple=True)
    purge_operation = grids.GridOperation(
        "Purge",
        condition=(lambda item: item.deleted and not item.purged),
        allow_multiple=True)

    @web.expose
    @web.require_admin
    def browse_repositories(self, trans, **kwd):
        # We add parameters to the keyword dict in this method in order to rename the param
        # with an "f-" prefix, simulating filtering by clicking a search link.  We have
        # to take this approach because the "-" character is illegal in HTTP requests.
        if 'operation' in kwd:
            operation = kwd['operation'].lower()
            if operation == "view_or_manage_repository":
                return trans.response.send_redirect(
                    web.url_for(controller='repository',
                                action='browse_repositories',
                                **kwd))
            elif operation == "edit_repository":
                return trans.response.send_redirect(
                    web.url_for(controller='repository',
                                action='edit_repository',
                                **kwd))
            elif operation == "repositories_by_user":
                # Eliminate the current filters if any exist.
                for k, v in list(kwd.items()):
                    if k.startswith('f-'):
                        del kwd[k]
                if 'user_id' in kwd:
                    user = suc.get_user(trans.app, kwd['user_id'])
                    kwd['f-email'] = user.email
                    del kwd['user_id']
                else:
                    # The received id is the repository id, so we need to get the id of the user
                    # that uploaded the repository.
                    repository_id = kwd.get('id', None)
                    repository = repository_util.get_repository_in_tool_shed(
                        trans.app, repository_id)
                    kwd['f-email'] = repository.user.email
            elif operation == "repositories_by_category":
                # Eliminate the current filters if any exist.
                for k, v in list(kwd.items()):
                    if k.startswith('f-'):
                        del kwd[k]
                category_id = kwd.get('id', None)
                category = suc.get_category(trans.app, category_id)
                kwd['f-Category.name'] = category.name
            elif operation == "receive email alerts":
                if kwd['id']:
                    kwd['caller'] = 'browse_repositories'
                    return trans.response.send_redirect(
                        web.url_for(controller='repository',
                                    action='set_email_alerts',
                                    **kwd))
                else:
                    del kwd['operation']
            elif operation == 'delete':
                return self.delete_repository(trans, **kwd)
            elif operation == "undelete":
                return self.undelete_repository(trans, **kwd)
        # The changeset_revision_select_field in the RepositoryGrid performs a refresh_on_change
        # which sends in request parameters like changeset_revison_1, changeset_revision_2, etc.  One
        # of the many select fields on the grid performed the refresh_on_change, so we loop through
        # all of the received values to see which value is not the repository tip.  If we find it, we
        # know the refresh_on_change occurred, and we have the necessary repository id and change set
        # revision to pass on.
        for k, v in kwd.items():
            changeset_revision_str = 'changeset_revision_'
            if k.startswith(changeset_revision_str):
                repository_id = trans.security.encode_id(
                    int(k.lstrip(changeset_revision_str)))
                repository = repository_util.get_repository_in_tool_shed(
                    trans.app, repository_id)
                if repository.tip() != v:
                    return trans.response.send_redirect(
                        web.url_for(controller='repository',
                                    action='browse_repositories',
                                    operation='view_or_manage_repository',
                                    id=trans.security.encode_id(repository.id),
                                    changeset_revision=v))
        # Render the list view
        return self.repository_grid(trans, **kwd)

    @web.expose
    @web.require_admin
    def browse_repository_metadata(self, trans, **kwd):
        if 'operation' in kwd:
            operation = kwd['operation'].lower()
            if operation == "delete":
                return self.delete_repository_metadata(trans, **kwd)
            if operation == "view_or_manage_repository_revision":
                # The received id is a RepositoryMetadata object id, so we need to get the
                # associated Repository and redirect to view_or_manage_repository with the
                # changeset_revision.
                repository_metadata = metadata_util.get_repository_metadata_by_id(
                    trans.app, kwd['id'])
                repository = repository_metadata.repository
                kwd['id'] = trans.security.encode_id(repository.id)
                kwd['changeset_revision'] = repository_metadata.changeset_revision
                kwd['operation'] = 'view_or_manage_repository'
                return trans.response.send_redirect(
                    web.url_for(controller='repository',
                                action='browse_repositories',
                                **kwd))
        return self.repository_metadata_grid(trans, **kwd)

    @web.expose
    @web.require_admin
    def create_category(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        status = kwd.get('status', 'done')
        name = kwd.get('name', '').strip()
        description = kwd.get('description', '').strip()
        if kwd.get('create_category_button', False):
            if not name or not description:
                message = 'Enter a valid name and a description'
                status = 'error'
            elif suc.get_category_by_name(trans.app, name):
                message = 'A category with that name already exists'
                status = 'error'
            else:
                # Create the category
                category = trans.app.model.Category(name=name,
                                                    description=description)
                trans.sa_session.add(category)
                trans.sa_session.flush()
                # Update the Tool Shed's repository registry.
                trans.app.repository_registry.add_category_entry(category)
                message = "Category '%s' has been created" % escape(
                    category.name)
                status = 'done'
                trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='manage_categories',
                                message=message,
                                status=status))
        return trans.fill_template(
            '/webapps/tool_shed/category/create_category.mako',
            name=name,
            description=description,
            message=message,
            status=status)

    @web.expose
    @web.require_admin
    def delete_repository(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        status = kwd.get('status', 'done')
        id = kwd.get('id', None)
        if id:
            # Deleting multiple items is currently not allowed (allow_multiple=False), so there will only be 1 id.
            ids = util.listify(id)
            count = 0
            deleted_repositories = ""
            for repository_id in ids:
                repository = repository_util.get_repository_in_tool_shed(
                    trans.app, repository_id)
                if repository:
                    if not repository.deleted:
                        # Mark all installable repository_metadata records as not installable.
                        for repository_metadata in repository.downloadable_revisions:
                            repository_metadata.downloadable = False
                            trans.sa_session.add(repository_metadata)
                        # Mark the repository admin role as deleted.
                        repository_admin_role = repository.admin_role
                        if repository_admin_role is not None:
                            repository_admin_role.deleted = True
                            trans.sa_session.add(repository_admin_role)
                        repository.deleted = True
                        trans.sa_session.add(repository)
                        trans.sa_session.flush()
                        # Update the repository registry.
                        trans.app.repository_registry.remove_entry(repository)
                        count += 1
                        deleted_repositories += " %s " % repository.name
            if count:
                message = "Deleted %d %s: %s" % (
                    count, inflector.cond_plural(
                        len(ids), "repository"), escape(deleted_repositories))
            else:
                message = "All selected repositories were already marked deleted."
        else:
            message = "No repository ids received for deleting."
            status = 'error'
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='browse_repositories',
                        message=util.sanitize_text(message),
                        status=status))

    @web.expose
    @web.require_admin
    def delete_repository_metadata(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        status = kwd.get('status', 'done')
        id = kwd.get('id', None)
        if id:
            ids = util.listify(id)
            count = 0
            for repository_metadata_id in ids:
                repository_metadata = metadata_util.get_repository_metadata_by_id(
                    trans.app, repository_metadata_id)
                trans.sa_session.delete(repository_metadata)
                trans.sa_session.flush()
                count += 1
            if count:
                message = "Deleted %d repository metadata %s" % (
                    count, inflector.cond_plural(len(ids), "record"))
        else:
            message = "No repository metadata ids received for deleting."
            status = 'error'
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='browse_repository_metadata',
                        message=util.sanitize_text(message),
                        status=status))

    @web.expose
    @web.require_admin
    def edit_category(self, trans, **kwd):
        '''Handle requests to edit TS category name or description'''
        message = escape(kwd.get('message', ''))
        status = kwd.get('status', 'done')
        id = kwd.get('id', None)
        if not id:
            message = "No category ids received for editing"
            trans.response.send_redirect(
                web.url_for(controller='admin',
                            action='manage_categories',
                            message=message,
                            status='error'))
        category = suc.get_category(trans.app, id)
        original_category_name = str(category.name)
        original_category_description = str(category.description)
        if kwd.get('edit_category_button', False):
            flush_needed = False
            new_name = kwd.get('name', '').strip()
            new_description = kwd.get('description', '').strip()
            if original_category_name != new_name:
                if not new_name:
                    message = 'Enter a valid name'
                    status = 'error'
                elif original_category_name != new_name and suc.get_category_by_name(
                        trans.app, new_name):
                    message = 'A category with that name already exists'
                    status = 'error'
                else:
                    category.name = new_name
                    flush_needed = True
            if original_category_description != new_description:
                category.description = new_description
                if not flush_needed:
                    flush_needed = True
            if flush_needed:
                trans.sa_session.add(category)
                trans.sa_session.flush()
                if original_category_name != new_name:
                    # Update the Tool Shed's repository registry.
                    trans.app.repository_registry.edit_category_entry(
                        original_category_name, new_name)
                message = "The information has been saved for category '%s'" % escape(
                    category.name)
                status = 'done'
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='manage_categories',
                                message=message,
                                status=status))
        return trans.fill_template(
            '/webapps/tool_shed/category/edit_category.mako',
            category=category,
            message=message,
            status=status)

    @web.expose
    @web.require_admin
    def manage_categories(self, trans, **kwd):
        if 'f-free-text-search' in kwd:
            # Trick to enable searching repository name, description from the CategoryGrid.
            # What we've done is rendered the search box for the RepositoryGrid on the grid.mako
            # template for the CategoryGrid.  See ~/templates/webapps/tool_shed/category/grid.mako.
            # Since we are searching repositories and not categories, redirect to browse_repositories().
            return trans.response.send_redirect(
                web.url_for(controller='admin',
                            action='browse_repositories',
                            **kwd))
        if 'operation' in kwd:
            operation = kwd['operation'].lower()
            if operation == "create":
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='create_category',
                                **kwd))
            elif operation == "delete":
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='mark_category_deleted',
                                **kwd))
            elif operation == "undelete":
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='undelete_category',
                                **kwd))
            elif operation == "purge":
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='purge_category',
                                **kwd))
            elif operation == "edit":
                return trans.response.send_redirect(
                    web.url_for(controller='admin',
                                action='edit_category',
                                **kwd))
        return self.manage_category_grid(trans, **kwd)

    @web.expose
    @web.require_admin
    def regenerate_statistics(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        status = kwd.get('status', 'done')
        if 'regenerate_statistics_button' in kwd:
            trans.app.shed_counter.generate_statistics()
            message = "Successfully regenerated statistics"
        return trans.fill_template('/webapps/tool_shed/admin/statistics.mako',
                                   message=message,
                                   status=status)

    @web.expose
    @web.require_admin
    def manage_role_associations(self, trans, **kwd):
        """Manage users, groups and repositories associated with a role."""
        role_id = kwd.get('id', None)
        role = repository_util.get_role_by_id(trans.app, role_id)
        # We currently only have a single role associated with a repository, the repository admin role.
        repository_role_association = role.repositories[0]
        repository = repository_role_association.repository
        associations_dict = repository_util.handle_role_associations(
            trans.app, role, repository, **kwd)
        in_users = associations_dict.get('in_users', [])
        out_users = associations_dict.get('out_users', [])
        in_groups = associations_dict.get('in_groups', [])
        out_groups = associations_dict.get('out_groups', [])
        message = associations_dict.get('message', '')
        status = associations_dict.get('status', 'done')
        return trans.fill_template('/webapps/tool_shed/role/role.mako',
                                   in_admin_controller=True,
                                   repository=repository,
                                   role=role,
                                   in_users=in_users,
                                   out_users=out_users,
                                   in_groups=in_groups,
                                   out_groups=out_groups,
                                   message=message,
                                   status=status)

    @web.expose
    @web.require_admin
    def reset_metadata_on_selected_repositories_in_tool_shed(
            self, trans, **kwd):
        rmm = repository_metadata_manager.RepositoryMetadataManager(
            trans.app, trans.user)
        if 'reset_metadata_on_selected_repositories_button' in kwd:
            message, status = rmm.reset_metadata_on_selected_repositories(
                **kwd)
        else:
            message = escape(util.restore_text(kwd.get('message', '')))
            status = kwd.get('status', 'done')
        repositories_select_field = rmm.build_repository_ids_select_field(
            name='repository_ids',
            multiple=True,
            display='checkboxes',
            my_writable=False)
        return trans.fill_template(
            '/webapps/tool_shed/common/reset_metadata_on_selected_repositories.mako',
            repositories_select_field=repositories_select_field,
            message=message,
            status=status)

    @web.expose
    @web.require_admin
    def undelete_repository(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        id = kwd.get('id', None)
        if id:
            # Undeleting multiple items is currently not allowed (allow_multiple=False), so there will only be 1 id.
            ids = util.listify(id)
            count = 0
            undeleted_repositories = ""
            for repository_id in ids:
                repository = repository_util.get_repository_in_tool_shed(
                    trans.app, repository_id)
                if repository:
                    if repository.deleted:
                        # Inspect all repository_metadata records to determine those that are installable, and mark
                        # them accordingly.
                        for repository_metadata in repository.metadata_revisions:
                            metadata = repository_metadata.metadata
                            if metadata:
                                if metadata_util.is_downloadable(metadata):
                                    repository_metadata.downloadable = True
                                    trans.sa_session.add(repository_metadata)
                        # Mark the repository admin role as not deleted.
                        repository_admin_role = repository.admin_role
                        if repository_admin_role is not None:
                            repository_admin_role.deleted = False
                            trans.sa_session.add(repository_admin_role)
                        repository.deleted = False
                        trans.sa_session.add(repository)
                        trans.sa_session.flush()
                        if not repository.deprecated:
                            # Update the repository registry.
                            trans.app.repository_registry.add_entry(repository)
                        count += 1
                        undeleted_repositories += " %s" % repository.name
            if count:
                message = "Undeleted %d %s: %s" % (
                    count, inflector.cond_plural(
                        count, "repository"), undeleted_repositories)
            else:
                message = "No selected repositories were marked deleted, so they could not be undeleted."
        else:
            message = "No repository ids received for undeleting."
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='browse_repositories',
                        message=util.sanitize_text(message),
                        status='done'))

    @web.expose
    @web.require_admin
    def mark_category_deleted(self, trans, **kwd):
        # TODO: We should probably eliminate the Category.deleted column since it really makes no
        # sense to mark a category as deleted (category names and descriptions can be changed instead).
        # If we do this, and the following 2 methods can be eliminated.
        message = escape(kwd.get('message', ''))
        id = kwd.get('id', None)
        if id:
            ids = util.listify(id)
            message = "Deleted %d categories: " % len(ids)
            for category_id in ids:
                category = suc.get_category(trans.app, category_id)
                category.deleted = True
                trans.sa_session.add(category)
                trans.sa_session.flush()
                # Update the Tool Shed's repository registry.
                trans.app.repository_registry.remove_category_entry(category)
                message += " %s " % escape(category.name)
        else:
            message = "No category ids received for deleting."
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='manage_categories',
                        message=util.sanitize_text(message),
                        status='done'))

    @web.expose
    @web.require_admin
    def purge_category(self, trans, **kwd):
        # This method should only be called for a Category that has previously been deleted.
        # Purging a deleted Category deletes all of the following from the database:
        # - RepoitoryCategoryAssociations where category_id == Category.id
        message = escape(kwd.get('message', ''))
        id = kwd.get('id', None)
        if id:
            ids = util.listify(id)
            count = 0
            purged_categories = ""
            message = "Purged %d categories: " % len(ids)
            for category_id in ids:
                category = suc.get_category(trans.app, category_id)
                if category.deleted:
                    # Delete RepositoryCategoryAssociations
                    for rca in category.repositories:
                        trans.sa_session.delete(rca)
                    trans.sa_session.flush()
                    purged_categories += " %s " % category.name
            message = "Purged %d categories: %s" % (count,
                                                    escape(purged_categories))
        else:
            message = "No category ids received for purging."
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='manage_categories',
                        message=util.sanitize_text(message),
                        status='done'))

    @web.expose
    @web.require_admin
    def undelete_category(self, trans, **kwd):
        message = escape(kwd.get('message', ''))
        id = kwd.get('id', None)
        if id:
            ids = util.listify(id)
            count = 0
            undeleted_categories = ""
            for category_id in ids:
                category = suc.get_category(trans.app, category_id)
                if category.deleted:
                    category.deleted = False
                    trans.sa_session.add(category)
                    trans.sa_session.flush()
                    # Update the Tool Shed's repository registry.
                    trans.app.repository_registry.add_category_entry(category)
                    count += 1
                    undeleted_categories += " %s" % category.name
            message = "Undeleted %d categories: %s" % (
                count, escape(undeleted_categories))
        else:
            message = "No category ids received for undeleting."
        trans.response.send_redirect(
            web.url_for(controller='admin',
                        action='manage_categories',
                        message=util.sanitize_text(message),
                        status='done'))
예제 #6
0
class RepositoryMetadataGrid(grids.Grid):

    class IdColumn(grids.IntegerColumn):

        def get_value(self, trans, grid, repository_metadata):
            return repository_metadata.id

    class NameColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            return escape(repository_metadata.repository.name)

    class OwnerColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            return escape(repository_metadata.repository.user.username)

    class RevisionColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            repository = repository_metadata.repository
            return hg_util.get_revision_label(trans.app,
                                              repository,
                                              repository_metadata.changeset_revision,
                                              include_date=True,
                                              include_hash=True)

    class ToolsColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            tools_str = '0'
            if repository_metadata:
                metadata = repository_metadata.metadata
                if metadata:
                    if 'tools' in metadata:
                        # We used to display the following, but grid was too cluttered.
                        # for tool_metadata_dict in metadata[ 'tools' ]:
                        #    tools_str += '%s <b>%s</b><br/>' % ( tool_metadata_dict[ 'id' ], tool_metadata_dict[ 'version' ] )
                        return '%d' % len(metadata['tools'])
            return tools_str

    class DatatypesColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            datatypes_str = '0'
            if repository_metadata:
                metadata = repository_metadata.metadata
                if metadata:
                    if 'datatypes' in metadata:
                        # We used to display the following, but grid was too cluttered.
                        # for datatype_metadata_dict in metadata[ 'datatypes' ]:
                        #    datatypes_str += '%s<br/>' % datatype_metadata_dict[ 'extension' ]
                        return '%d' % len(metadata['datatypes'])
            return datatypes_str

    class WorkflowsColumn(grids.TextColumn):

        def get_value(self, trans, grid, repository_metadata):
            workflows_str = '0'
            if repository_metadata:
                metadata = repository_metadata.metadata
                if metadata:
                    if 'workflows' in metadata:
                        # We used to display the following, but grid was too cluttered.
                        # workflows_str += '<b>Workflows:</b><br/>'
                        # metadata[ 'workflows' ] is a list of tuples where each contained tuple is
                        # [ <relative path to the .ga file in the repository>, <exported workflow dict> ]
                        # workflow_tups = metadata[ 'workflows' ]
                        # workflow_metadata_dicts = [ workflow_tup[1] for workflow_tup in workflow_tups ]
                        # for workflow_metadata_dict in workflow_metadata_dicts:
                        #    workflows_str += '%s<br/>' % workflow_metadata_dict[ 'name' ]
                        return '%d' % len(metadata['workflows'])
            return workflows_str

    class DeletedColumn(grids.BooleanColumn):

        def get_value(self, trans, grid, repository_metadata):
            if repository_metadata.repository.deleted:
                return 'yes'
            return ''

    class DeprecatedColumn(grids.BooleanColumn):

        def get_value(self, trans, grid, repository_metadata):
            if repository_metadata.repository.deprecated:
                return 'yes'
            return ''

    class MaliciousColumn(grids.BooleanColumn):

        def get_value(self, trans, grid, repository_metadata):
            if repository_metadata.malicious:
                return 'yes'
            return ''

    # Grid definition
    title = "Repository Metadata"
    model_class = model.RepositoryMetadata
    default_sort_key = "name"
    use_hide_message = False
    columns = [
        IdColumn("Id",
                 visible=False,
                 attach_popup=False),
        NameColumn("Name",
                   key="name",
                   model_class=model.Repository,
                   link=(lambda item: dict(operation="view_or_manage_repository_revision", id=item.id)),
                   attach_popup=True),
        OwnerColumn("Owner", attach_popup=False),
        RevisionColumn("Revision", attach_popup=False),
        ToolsColumn("Tools", attach_popup=False),
        DatatypesColumn("Datatypes", attach_popup=False),
        WorkflowsColumn("Workflows", attach_popup=False),
        DeletedColumn("Deleted", attach_popup=False),
        DeprecatedColumn("Deprecated", attach_popup=False),
        MaliciousColumn("Malicious", attach_popup=False)
    ]
    columns.append(grids.MulticolFilterColumn("Search repository name",
                                              cols_to_filter=[columns[1]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    operations = [grids.GridOperation("Delete",
                                      allow_multiple=False,
                                      allow_popup=True,
                                      async_compatible=False,
                                      confirm="Repository metadata records cannot be recovered after they are deleted. Click OK to delete the selected items.")]

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.RepositoryMetadata) \
                               .join(model.Repository.table)
예제 #7
0
class GroupGrid(grids.Grid):

    class NameColumn(grids.TextColumn):

        def get_value(self, trans, grid, group):
            return str(group.name)

    class StatusColumn(grids.GridColumn):

        def get_value(self, trans, grid, group):
            if group.deleted:
                return "deleted"
            return ""

    class RolesColumn(grids.GridColumn):

        def get_value(self, trans, grid, group):
            if group.roles:
                return len(group.roles)
            return 0

    class UsersColumn(grids.GridColumn):

        def get_value(self, trans, grid, group):
            if group.members:
                return len(group.members)
            return 0

    title = "Groups"
    model_class = model.Group
    default_sort_key = "name"
    columns = [
        NameColumn("Name",
                   key="name",
                   link=(lambda item: dict(operation="Manage users and roles", id=item.id)),
                   attach_popup=True),
        UsersColumn("Users", attach_popup=False),
        RolesColumn("Roles", attach_popup=False),
        StatusColumn("Status", attach_popup=False),
        # Columns that are valid for filtering but are not visible.
        grids.DeletedColumn("Deleted",
                            key="deleted",
                            visible=False,
                            filterable="advanced")
    ]
    columns.append(grids.MulticolFilterColumn("Search",
                                              cols_to_filter=[columns[0]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    global_actions = [
        grids.GridAction("Add new group",
                         dict(controller='admin', action='groups', operation='create'))
    ]
    operations = [grids.GridOperation("Rename",
                                      condition=(lambda item: not item.deleted),
                                      allow_multiple=False,
                                      url_args=dict(action="rename_group")),
                  grids.GridOperation("Delete",
                                      condition=(lambda item: not item.deleted),
                                      allow_multiple=True,
                                      url_args=dict(action="mark_group_deleted")),
                  grids.GridOperation("Undelete",
                                      condition=(lambda item: item.deleted),
                                      allow_multiple=True,
                                      url_args=dict(action="undelete_group")),
                  grids.GridOperation("Purge",
                                      condition=(lambda item: item.deleted),
                                      allow_multiple=True,
                                      url_args=dict(action="purge_group"))]
    standard_filters = [
        grids.GridColumnFilter("Active", args=dict(deleted=False)),
        grids.GridColumnFilter("Deleted", args=dict(deleted=True)),
        grids.GridColumnFilter("All", args=dict(deleted='All'))
    ]

    use_paging = False
예제 #8
0
class UserGrid(grids.Grid):

    class UserLoginColumn(grids.TextColumn):

        def get_value(self, trans, grid, user):
            return escape(user.email)

    class UserNameColumn(grids.TextColumn):

        def get_value(self, trans, grid, user):
            if user.username:
                return escape(user.username)
            return 'not set'

    class GroupsColumn(grids.GridColumn):

        def get_value(self, trans, grid, user):
            if user.groups:
                return len(user.groups)
            return 0

    class RolesColumn(grids.GridColumn):

        def get_value(self, trans, grid, user):
            if user.roles:
                return len(user.roles)
            return 0

    class ExternalColumn(grids.GridColumn):

        def get_value(self, trans, grid, user):
            if user.external:
                return 'yes'
            return 'no'

    class LastLoginColumn(grids.GridColumn):

        def get_value(self, trans, grid, user):
            if user.galaxy_sessions:
                return self.format(user.galaxy_sessions[0].update_time)
            return 'never'

    class StatusColumn(grids.GridColumn):

        def get_value(self, trans, grid, user):
            if user.purged:
                return "purged"
            elif user.deleted:
                return "deleted"
            return ""

    class EmailColumn(grids.GridColumn):

        def filter(self, trans, user, query, column_filter):
            if column_filter == 'All':
                return query
            return query.filter(and_(model.Tool.table.c.user_id == model.User.table.c.id,
                                     model.User.table.c.email == column_filter))

    title = "Users"
    model_class = model.User
    default_sort_key = "email"
    columns = [
        UserLoginColumn("Email",
                        key="email",
                        link=(lambda item: dict(operation="information", id=item.id)),
                        attach_popup=True,
                        filterable="advanced"),
        UserNameColumn("User Name",
                       key="username",
                       attach_popup=False,
                       filterable="advanced"),
        GroupsColumn("Groups", attach_popup=False),
        RolesColumn("Roles", attach_popup=False),
        ExternalColumn("External", attach_popup=False),
        LastLoginColumn("Last Login", format=time_ago),
        StatusColumn("Status", attach_popup=False),
        # Columns that are valid for filtering but are not visible.
        EmailColumn("Email",
                    key="email",
                    visible=False)
    ]
    columns.append(grids.MulticolFilterColumn("Search",
                                              cols_to_filter=[columns[0], columns[1]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    global_actions = [
        grids.GridAction("Create new user",
                         dict(controller='admin', action='users', operation='create'))
    ]
    operations = [
        grids.GridOperation("Manage Roles and Groups",
                            condition=(lambda item: not item.deleted),
                            allow_multiple=False,
                            url_args=dict(action="manage_roles_and_groups_for_user")),
        grids.GridOperation("Reset Password",
                            condition=(lambda item: not item.deleted),
                            allow_multiple=True,
                            allow_popup=False,
                            url_args=dict(action="reset_user_password"))
    ]
    standard_filters = [
        grids.GridColumnFilter("Active", args=dict(deleted=False)),
        grids.GridColumnFilter("Deleted", args=dict(deleted=True, purged=False)),
        grids.GridColumnFilter("Purged", args=dict(purged=True)),
        grids.GridColumnFilter("All", args=dict(deleted='All'))
    ]

    use_paging = False

    def get_current_item(self, trans, **kwargs):
        return trans.user
예제 #9
0
class RoleGrid(grids.Grid):

    class NameColumn(grids.TextColumn):

        def get_value(self, trans, grid, role):
            return escape(str(role.name))

    class DescriptionColumn(grids.TextColumn):

        def get_value(self, trans, grid, role):
            if role.description:
                return str(role.description)
            return ''

    class TypeColumn(grids.TextColumn):
        def get_value(self, trans, grid, role):
            return str(role.type)

    class StatusColumn(grids.GridColumn):

        def get_value(self, trans, grid, role):
            if role.deleted:
                return "deleted"
            return ""

    class GroupsColumn(grids.GridColumn):

        def get_value(self, trans, grid, role):
            if role.groups:
                return len(role.groups)
            return 0

    class RepositoriesColumn(grids.GridColumn):

        def get_value(self, trans, grid, role):
            if role.repositories:
                return len(role.repositories)
            return 0

    class UsersColumn(grids.GridColumn):

        def get_value(self, trans, grid, role):
            if role.users:
                return len(role.users)
            return 0

    title = "Roles"
    model_class = model.Role
    default_sort_key = "name"
    columns = [
        NameColumn("Name",
                   key="name",
                   link=(lambda item: dict(operation="Manage role associations", id=item.id)),
                   attach_popup=True,
                   filterable="advanced"),
        DescriptionColumn("Description",
                          key='description',
                          attach_popup=False,
                          filterable="advanced"),
        GroupsColumn("Groups", attach_popup=False),
        RepositoriesColumn("Repositories", attach_popup=False),
        UsersColumn("Users", attach_popup=False),
        # Columns that are valid for filtering but are not visible.
        grids.DeletedColumn("Deleted",
                            key="deleted",
                            visible=False,
                            filterable="advanced")
    ]
    columns.append(grids.MulticolFilterColumn("Search",
                                              cols_to_filter=[columns[0]],
                                              key="free-text-search",
                                              visible=False,
                                              filterable="standard"))
    global_actions = [
        grids.GridAction("Add new role",
                         dict(controller='admin', action='roles', operation='create'))
    ]
    # Repository admin roles currently do not have any operations since they are managed automatically based
    # on other events.  For example, if a repository is renamed, its associated admin role is automatically
    # renamed accordingly and if a repository is deleted its associated admin role is automatically deleted.
    operations = [grids.GridOperation("Rename",
                                      condition=(lambda item: not item.deleted and not item.is_repository_admin_role),
                                      allow_multiple=False,
                                      url_args=dict(action="rename_role")),
                  grids.GridOperation("Delete",
                                      condition=(lambda item: not item.deleted and not item.is_repository_admin_role),
                                      allow_multiple=True,
                                      url_args=dict(action="mark_role_deleted")),
                  grids.GridOperation("Undelete",
                                      condition=(lambda item: item.deleted and not item.is_repository_admin_role),
                                      allow_multiple=True,
                                      url_args=dict(action="undelete_role")),
                  grids.GridOperation("Purge",
                                      condition=(lambda item: item.deleted and not item.is_repository_admin_role),
                                      allow_multiple=True,
                                      url_args=dict(action="purge_role"))]
    standard_filters = [
        grids.GridColumnFilter("Active", args=dict(deleted=False)),
        grids.GridColumnFilter("Deleted", args=dict(deleted=True)),
        grids.GridColumnFilter("All", args=dict(deleted='All'))
    ]

    use_paging = False

    def apply_query_filter(self, trans, query, **kwd):
        return query.filter(model.Role.type != model.Role.types.PRIVATE)
예제 #10
0
class RepositoriesWithReviewsGrid(RepositoryGrid):
    # This grid filters out repositories that have been marked as either deprecated or deleted.

    class WithReviewsRevisionColumn(grids.GridColumn):
        def get_value(self, trans, grid, repository):
            # Restrict to revisions that have been reviewed.
            if repository.reviews:
                rval = ''
                repo = repository.hg_repo
                for review in repository.reviews:
                    changeset_revision = review.changeset_revision
                    rev, label = hg_util.get_rev_label_from_changeset_revision(
                        repo, changeset_revision)
                    rval += '<a href="manage_repository_reviews_of_revision?id=%s&changeset_revision=%s">%s</a><br/>' % \
                        (trans.security.encode_id(repository.id), changeset_revision, label)
                return rval
            return ''

    class WithoutReviewsRevisionColumn(grids.GridColumn):
        def get_value(self, trans, grid, repository):
            # Restrict the options to revisions that have not yet been reviewed.
            repository_metadata_revisions = metadata_util.get_repository_metadata_revisions_for_review(
                repository, reviewed=False)
            if repository_metadata_revisions:
                rval = ''
                for repository_metadata in repository_metadata_revisions:
                    rev, label, changeset_revision = \
                        hg_util.get_rev_label_changeset_revision_from_repository_metadata(trans.app,
                                                                                          repository_metadata,
                                                                                          repository=repository,
                                                                                          include_date=True,
                                                                                          include_hash=False)
                    rval += '<a href="manage_repository_reviews_of_revision?id=%s&changeset_revision=%s">%s</a><br/>' % \
                        (trans.security.encode_id(repository.id), changeset_revision, label)
                return rval
            return ''

    class ReviewersColumn(grids.TextColumn):
        def get_value(self, trans, grid, repository):
            rval = ''
            if repository.reviewers:
                for user in repository.reviewers:
                    rval += '<a class="view-info" href="repository_reviews_by_user?id=%s">' % trans.security.encode_id(
                        user.id)
                    rval += '%s</a> | ' % user.username
                if rval[-3:] == ' | ':
                    rval = rval[:-3]
            return rval

    class RatingColumn(grids.TextColumn):
        def get_value(self, trans, grid, repository):
            rval = ''
            for review in repository.reviews:
                if review.rating:
                    for index in range(1, 6):
                        rval += '<input '
                        rval += 'name="star1-%s" ' % trans.security.encode_id(
                            review.id)
                        rval += 'type="radio" '
                        rval += 'class="community_rating_star star" '
                        rval += 'disabled="disabled" '
                        rval += 'value="%s" ' % str(review.rating)
                        if review.rating > (index - 0.5) and review.rating < (
                                index + 0.5):
                            rval += 'checked="checked" '
                        rval += '/>'
                rval += '<br/>'
            return rval

    class ApprovedColumn(grids.TextColumn):
        def get_value(self, trans, grid, repository):
            rval = ''
            for review in repository.reviews:
                if review.approved:
                    rval += '%s<br/>' % review.approved
            return rval

    title = "All reviewed repositories"
    model_class = model.Repository
    template = '/webapps/tool_shed/repository_review/grid.mako'
    default_sort_key = "Repository.name"
    columns = [
        RepositoryGrid.NameColumn(
            "Repository name",
            key="name",
            link=(lambda item: dict(operation="view_or_manage_repository",
                                    id=item.id)),
            attach_popup=True),
        RepositoryGrid.UserColumn("Owner",
                                  model_class=model.User,
                                  attach_popup=False,
                                  key="User.username"),
        WithReviewsRevisionColumn("Reviewed revisions"),
        ReviewersColumn("Reviewers", attach_popup=False),
        RatingColumn("Rating", attach_popup=False),
        ApprovedColumn("Approved", attach_popup=False)
    ]
    columns.append(
        grids.MulticolFilterColumn("Search repository name",
                                   cols_to_filter=[columns[0]],
                                   key="free-text-search",
                                   visible=False,
                                   filterable="standard"))
    operations = [
        grids.GridOperation("Inspect repository revisions",
                            allow_multiple=False,
                            condition=(lambda item: not item.deleted),
                            async_compatible=False)
    ]

    def build_initial_query(self, trans, **kwd):
        return trans.sa_session.query(model.Repository) \
                               .filter(and_(model.Repository.table.c.deleted == false(),
                                            model.Repository.table.c.deprecated == false())) \
                               .join((model.RepositoryReview.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id)) \
                               .join((model.User.table, model.User.table.c.id == model.Repository.table.c.user_id)) \
                               .outerjoin((model.ComponentReview.table, model.ComponentReview.table.c.repository_review_id == model.RepositoryReview.table.c.id)) \
                               .outerjoin((model.Component.table, model.Component.table.c.id == model.ComponentReview.table.c.component_id))
예제 #11
0
class RepositoryReviewsByUserGrid(grids.Grid):
    # This grid filters out repositories that have been marked as deprecated.

    class RepositoryNameColumn(grids.TextColumn):
        def get_value(self, trans, grid, review):
            return escape(review.repository.name)

    class RepositoryDescriptionColumn(grids.TextColumn):
        def get_value(self, trans, grid, review):
            return escape(review.repository.description)

    class RevisionColumn(grids.TextColumn):
        def get_value(self, trans, grid, review):
            encoded_review_id = trans.security.encode_id(review.id)
            rval = '<a class="action-button" href="'
            if review.user == trans.user:
                rval += 'edit_review'
            else:
                rval += 'browse_review'
            revision_label = hg_util.get_revision_label(
                trans.app,
                review.repository,
                review.changeset_revision,
                include_date=True,
                include_hash=False)
            rval += f'?id={encoded_review_id}">{revision_label}</a>'
            return rval

    class RatingColumn(grids.TextColumn):
        def get_value(self, trans, grid, review):
            if review.rating:
                for index in range(1, 6):
                    rval = '<input '
                    rval += 'name="star1-%s" ' % trans.security.encode_id(
                        review.id)
                    rval += 'type="radio" '
                    rval += 'class="community_rating_star star" '
                    rval += 'disabled="disabled" '
                    rval += 'value="%s" ' % str(review.rating)
                    if review.rating > (index -
                                        0.5) and review.rating < (index + 0.5):
                        rval += 'checked="checked" '
                    rval += '/>'
                return rval
            return ''

    title = "Reviews by user"
    model_class = model.RepositoryReview
    template = '/webapps/tool_shed/repository_review/grid.mako'
    default_sort_key = 'repository_id'
    use_hide_message = False
    columns = [
        RepositoryNameColumn(
            "Repository Name",
            model_class=model.Repository,
            key="Repository.name",
            link=(lambda item: dict(operation="view_or_manage_repository",
                                    id=item.id)),
            attach_popup=True),
        RepositoryDescriptionColumn("Description",
                                    model_class=model.Repository,
                                    key="Repository.description",
                                    attach_popup=False),
        RevisionColumn("Revision", attach_popup=False),
        RatingColumn("Rating", attach_popup=False),
    ]
    operations = [
        grids.GridOperation("Inspect repository revisions",
                            allow_multiple=False,
                            condition=(lambda item: not item.deleted),
                            async_compatible=False)
    ]
    num_rows_per_page = 50

    def build_initial_query(self, trans, **kwd):
        user_id = trans.security.decode_id(kwd['id'])
        return trans.sa_session.query(model.RepositoryReview) \
                               .filter(and_(model.RepositoryReview.table.c.deleted == false(),
                                            model.RepositoryReview.table.c.user_id == user_id)) \
                               .join((model.Repository.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id)) \
                               .filter(model.Repository.table.c.deprecated == false())