Remove repository review functionality from tool shed.

This commit is contained in:
John Chilton
2022-09-16 20:25:37 -04:00
parent fa35e66709
commit 44d6a34178
30 changed files with 9 additions and 3828 deletions
@@ -1,535 +0,0 @@
import logging
from markupsafe import escape
from sqlalchemy import (
and_,
false,
null,
or_,
true,
)
from galaxy.web.legacy_framework import grids
from tool_shed.grids.repository_grids import RepositoryGrid
from tool_shed.util import (
hg_util,
metadata_util,
)
from tool_shed.webapp import model
log = logging.getLogger(__name__)
class ComponentGrid(grids.Grid):
class NameColumn(grids.TextColumn):
def get_value(self, trans, grid, component):
return escape(component.name)
class DescriptionColumn(grids.TextColumn):
def get_value(self, trans, grid, component):
return escape(component.description)
title = "Repository review components"
model_class = model.Component
template = "/webapps/tool_shed/repository_review/grid.mako"
default_sort_key = "name"
use_hide_message = False
columns = [
NameColumn(
"Name", key="Component.name", link=(lambda item: dict(operation="edit", id=item.id)), attach_popup=False
),
DescriptionColumn("Description", key="Component.description", attach_popup=False),
]
global_actions = [
grids.GridAction(
"Add new component", dict(controller="repository_review", action="manage_components", operation="create")
)
]
num_rows_per_page = 50
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 += f'<a class="view-info" href="repository_reviews_by_user?id={trans.security.encode_id(user.id)}">'
rval += f"{user.username}</a> | "
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 += f'name="star1-{trans.security.encode_id(review.id)}" '
rval += 'type="radio" '
rval += 'class="community_rating_star star" '
rval += 'disabled="disabled" '
rval += f'value="{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 += f"{review.approved}<br/>"
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)
)
)
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)
)
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)
)
class RepositoriesReviewedByMeGrid(RepositoriesWithReviewsGrid):
# This grid filters out repositories that have been marked as either deprecated or deleted.
columns = [
RepositoriesWithReviewsGrid.NameColumn(
"Repository name",
key="name",
link=(lambda item: dict(operation="view_or_manage_repository", id=item.id)),
attach_popup=True,
),
RepositoriesWithReviewsGrid.UserColumn("Owner", attach_popup=False),
RepositoriesWithReviewsGrid.WithReviewsRevisionColumn("Reviewed revisions"),
RepositoriesWithReviewsGrid.ReviewersColumn("Reviewers", attach_popup=False),
RepositoriesWithReviewsGrid.RatingColumn("Rating", attach_popup=False),
RepositoriesWithReviewsGrid.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",
)
)
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,
)
)
.filter(model.RepositoryReview.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)
)
)
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 += f'name="star1-{trans.security.encode_id(review.id)}" '
rval += 'type="radio" '
rval += 'class="community_rating_star star" '
rval += 'disabled="disabled" '
rval += f'value="{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())
)
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)
)
)
class RepositoriesWithNoToolTestsGrid(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 that contain tools with no tests or test data"
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()))
.join(model.RepositoryMetadata.table)
.filter(
and_(
model.RepositoryMetadata.table.c.downloadable == true(),
model.RepositoryMetadata.table.c.includes_tools == true(),
model.RepositoryMetadata.table.c.tools_functionally_correct == false(),
)
)
.join(model.User.table)
)
+5 -35
View File
@@ -9,24 +9,12 @@ from tool_shed.util import (
log = logging.getLogger(__name__)
def build_approved_select_field(trans, name, selected_value=None, for_component=True):
options = [
("No", trans.model.ComponentReview.approved_states.NO),
("Yes", trans.model.ComponentReview.approved_states.YES),
]
if for_component:
options.append(("Not applicable", trans.model.ComponentReview.approved_states.NA))
if selected_value is None:
selected_value = trans.model.ComponentReview.approved_states.NA
select_field = SelectField(name=name)
for option_tup in options:
selected = selected_value and option_tup[1] == selected_value
select_field.add_option(option_tup[0], option_tup[1], selected=selected)
return select_field
def build_changeset_revision_select_field(
trans, repository, selected_value=None, add_id_to_name=True, downloadable=False, reviewed=False, not_reviewed=False
trans,
repository,
selected_value=None,
add_id_to_name=True,
downloadable=False,
):
"""
Build a SelectField whose options are the changeset_rev strings of certain revisions of the
@@ -38,24 +26,6 @@ def build_changeset_revision_select_field(
if downloadable:
# Restrict the options to downloadable revisions.
repository_metadata_revisions = repository.downloadable_revisions
elif reviewed:
# Restrict the options to revisions that have been reviewed.
repository_metadata_revisions = []
metadata_changeset_revision_hashes = []
for metadata_revision in repository.metadata_revisions:
metadata_changeset_revision_hashes.append(metadata_revision.changeset_revision)
for review in repository.reviews:
if review.changeset_revision in metadata_changeset_revision_hashes:
repository_metadata_revisions.append(review.repository_metadata)
elif not_reviewed:
# Restrict the options to revisions that have not yet been reviewed.
repository_metadata_revisions = []
reviewed_metadata_changeset_revision_hashes = []
for review in repository.reviews:
reviewed_metadata_changeset_revision_hashes.append(review.changeset_revision)
for metadata_revision in repository.metadata_revisions:
if metadata_revision.changeset_revision not in reviewed_metadata_changeset_revision_hashes:
repository_metadata_revisions.append(metadata_revision)
else:
# Restrict the options to all revisions that have associated metadata.
repository_metadata_revisions = repository.metadata_revisions
-65
View File
@@ -138,56 +138,6 @@ def get_repository_role_association(repository_id, role_id):
return rra
def get_repository_reviews(repository_id, reviewer_user_id=None, changeset_revision=None):
if reviewer_user_id and changeset_revision:
reviews = (
sa_session.query(model.RepositoryReview)
.filter(
and_(
model.RepositoryReview.table.c.repository_id == repository_id,
model.RepositoryReview.table.c.deleted == false(),
model.RepositoryReview.table.c.changeset_revision == changeset_revision,
model.RepositoryReview.table.c.user_id == reviewer_user_id,
)
)
.all()
)
elif reviewer_user_id:
reviews = (
sa_session.query(model.RepositoryReview)
.filter(
and_(
model.RepositoryReview.table.c.repository_id == repository_id,
model.RepositoryReview.table.c.deleted == false(),
model.RepositoryReview.table.c.user_id == reviewer_user_id,
)
)
.all()
)
else:
reviews = (
sa_session.query(model.RepositoryReview)
.filter(
and_(
model.RepositoryReview.table.c.repository_id == repository_id,
model.RepositoryReview.table.c.deleted == false(),
)
)
.all()
)
return reviews
def get_reviews_ordered_by_changeset_revision(repository_id, changelog_tuples, reviewer_user_id=None):
reviews = get_repository_reviews(repository_id, reviewer_user_id=reviewer_user_id)
ordered_reviews = []
for _ctx_rev, changeset_hash in changelog_tuples:
for review in reviews:
if str(review.changeset_revision) == str(changeset_hash):
ordered_reviews.append(review)
return ordered_reviews
def get_repository_by_id(repository_id):
return sa_session.query(model.Repository).filter(model.Repository.table.c.id == repository_id).first()
@@ -220,21 +170,6 @@ def get_repository_metadata_for_changeset_revision(repository_id, changeset_revi
return repository_metadata
def get_repository_review_by_user_id_changeset_revision(user_id, repository_id, changeset_revision):
review = (
sa_session.query(model.RepositoryReview)
.filter(
and_(
model.RepositoryReview.table.c.user_id == user_id,
model.RepositoryReview.table.c.repository_id == repository_id,
model.RepositoryReview.table.c.changeset_revision == changeset_revision,
)
)
.first()
)
return review
def get_role_by_name(role_name):
return sa_session.query(model.Role).filter(model.Role.table.c.name == role_name).first()
-110
View File
@@ -237,11 +237,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
fh.write(smart_str(content))
return fh.name
def add_repository_review_component(self, **kwd):
params = {"operation": "create"}
self.visit_url("/repository_review/create_component", params=params)
self.submit_form(button="create_component_button", **kwd)
def assign_admin_role(self, repository, user):
# As elsewhere, twill limits the possibility of submitting the form, this time due to not executing the javascript
# attached to the role selection form. Visit the action url directly with the necessary parameters.
@@ -262,11 +257,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
self.visit_url("/repository/browse_valid_categories", params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
def browse_component_review(self, review, strings_displayed=None, strings_not_displayed=None):
params = {"id": self.security.encode_id(review.id)}
self.visit_url("/repository_review/browse_review", params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
def browse_custom_datatypes(self, strings_displayed=None, strings_not_displayed=None):
url = "/repository/browse_datatypes"
self.visit_url(url)
@@ -517,34 +507,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
strings_not_displayed=None,
)
def create_repository_review(self, repository, review_contents_dict, changeset_revision=None, copy_from=None):
strings_displayed = []
if not copy_from:
strings_displayed.append("Begin your review")
strings_not_displayed = []
if not changeset_revision:
changeset_revision = self.get_repository_tip(repository)
params = {"changeset_revision": changeset_revision, "id": self.security.encode_id(repository.id)}
self.visit_url("/repository_review/create_review", params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
strings_displayed = []
if copy_from:
old_changeset_revision, review_id = copy_from
strings_displayed = [
"You have elected to create a new review",
"Select previous revision",
changeset_revision,
]
self.check_for_strings(strings_displayed)
strings_displayed = []
params = {
"changeset_revision": self.get_repository_tip(repository),
"id": self.security.encode_id(repository.id),
"previous_review_id": self.security.encode_id(review_id),
}
self.visit_url("/repository_review/create_review", params=params)
self.fill_review_form(review_contents_dict, strings_displayed, strings_not_displayed)
def create_user_in_galaxy(
self, cntrller="user", email="test@bx.psu.edu", password="testuser", username="admin-user", redirect=""
):
@@ -668,16 +630,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
self.visit_url(url, params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
def display_reviewed_repositories_owned_by_user(self, strings_displayed=None, strings_not_displayed=None):
url = "/repository_review/reviewed_repositories_i_own"
self.visit_url(url)
self.check_for_strings(strings_displayed, strings_not_displayed)
def display_repository_reviews_by_user(self, user, strings_displayed=None, strings_not_displayed=None):
params = {"id": self.security.encode_id(user.id)}
self.visit_url("/repository_review/repository_reviews_by_user", params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
def edit_repository_categories(
self, repository, categories_to_add=None, categories_to_remove=None, restore_original=True
):
@@ -754,25 +706,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
self.visit_url(url)
self.check_for_strings(strings_displayed, strings_not_displayed)
def fill_review_form(self, review_contents_dict, strings_displayed=None, strings_not_displayed=None):
kwd = dict()
changed = False
for label, contents in review_contents_dict.items():
if contents:
changed = True
kwd[f"{label}__ESEP__comment"] = contents["comment"]
kwd[f"{label}__ESEP__rating"] = contents["rating"]
if "private" in contents:
kwd[f"{label}__ESEP__private"] = contents["private"]
kwd[f"{label}__ESEP__approved"] = contents["approved"]
else:
kwd[f"{label}__ESEP__approved"] = "not_applicable"
self.check_for_strings(strings_displayed, strings_not_displayed)
self.submit_form(button="Workflows__ESEP__review_button", **kwd)
if changed:
strings_displayed.append("Reviews were saved")
self.check_for_strings(strings_displayed, strings_not_displayed)
def galaxy_token(self):
self.visit_galaxy_url("/")
html = self.last_page()
@@ -882,17 +815,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
def get_hg_repo(self, path):
return hg.repository(ui.ui(), path.encode("utf-8"))
def get_last_reviewed_revision_by_user(self, user, repository):
changelog_tuples = self.get_repository_changelog_tuples(repository)
reviews = test_db_util.get_reviews_ordered_by_changeset_revision(
repository.id, changelog_tuples, reviewer_user_id=user.id
)
if reviews:
last_review = reviews[-1]
else:
last_review = None
return last_review
def get_repositories_category_api(self, categories, strings_displayed=None, strings_not_displayed=None):
for category in categories:
url = f"/api/categories/{self.security.encode_id(category.id)}/repositories"
@@ -1261,11 +1183,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
self.visit_galaxy_url("/tool_runner", params=params)
self.check_for_strings(strings_displayed, strings_not_displayed)
def manage_review_components(self, strings_displayed=None, strings_not_displayed=None):
url = "/repository_review/manage_components"
self.visit_url(url)
self.check_for_strings(strings_displayed, strings_not_displayed)
def preview_repository_in_tool_shed(
self, name, owner, changeset_revision=None, strings_displayed=None, strings_not_displayed=None
):
@@ -1355,19 +1272,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
self.visit_url("/repository/reset_all_metadata", params=params)
self.check_for_strings(["All repository metadata has been reset."])
def review_repository(self, repository, review_contents_dict, user=None, changeset_revision=None):
strings_displayed = []
strings_not_displayed = []
if not changeset_revision:
changeset_revision = self.get_repository_tip(repository)
if user:
review = test_db_util.get_repository_review_by_user_id_changeset_revision(
user.id, repository.id, changeset_revision
)
params = {"id": self.security.encode_id(review.id)}
self.visit_url("/repository_review/edit_review", params=params)
self.fill_review_form(review_contents_dict, strings_displayed, strings_not_displayed)
def revoke_write_access(self, repository, username):
params = {"user_access_button": "Remove", "id": self.security.encode_id(repository.id), "remove_auth": username}
self.visit_url("/repository/manage_repository", params=params)
@@ -1651,20 +1555,6 @@ class ShedTwillTestCase(ShedBaseTestCase):
# or we know that the repository was not correctly installed!
assert found, f"No entry for {required_data_table_entry} in {self.shed_tool_data_table_conf}."
def verify_repository_reviews(self, repository, reviewer=None, strings_displayed=None, strings_not_displayed=None):
changeset_revision = self.get_repository_tip(repository)
# Verify that the currently logged in user has a repository review for the specified repository, reviewer, and changeset revision.
strings_displayed = [repository.name, reviewer.username]
self.display_reviewed_repositories_owned_by_user(strings_displayed=strings_displayed)
# Verify that the reviewer has reviewed the specified repository's changeset revision.
strings_displayed = [repository.name, repository.description]
self.display_repository_reviews_by_user(reviewer, strings_displayed=strings_displayed)
# Load the review and check for the components passed in strings_displayed.
review = test_db_util.get_repository_review_by_user_id_changeset_revision(
reviewer.id, repository.id, changeset_revision
)
self.browse_component_review(review, strings_displayed=strings_displayed)
def verify_tool_metadata_for_installed_repository(
self, installed_repository, strings_displayed=None, strings_not_displayed=None
):
@@ -1,666 +0,0 @@
from ..base.twilltestcase import (
common,
ShedTwillTestCase,
)
repository_name = "filtering_0400"
repository_description = "Galaxy filtering tool for test 0400"
repository_long_description = "Long description of Galaxy filtering tool for test 0400"
"""
1. Create users.
2. Grant reviewer role to test_user_2.
3. Check that the review components that are to be tested are defined in this tool shed instance.
4. Create a repository, owned by test_user_1, to be reviewed by test_user_2.
5. Review the datatypes component on the repository.
6. Check that no other components besides datatypes display as reviewed.
7. Review the functional tests component on the repository.
8. Check that only functional tests and datatypes display as reviewed.
9. Review the readme component on the repository.
10. Check that only functional tests, datatypes, and readme display as reviewed.
11. Review the repository dependencies component.
12. Check that only repository dependencies, functional tests, datatypes, and readme display as reviewed.
13. Review the tool dependencies component.
14. Check that only tool dependencies, repository dependencies, functional tests, datatypes, and readme display as reviewed.
15. Review the tools component.
16. Check that only tools, tool dependencies, repository dependencies, functional tests, datatypes, and readme display as reviewed.
17. Review the workflows component.
18. Check that all components display as reviewed.
19. Upload readme.txt to the repository.
20. Copy the previous review, and update the readme component review to reflect the existence of a readme file.
21. Check that the readme component review has been updated, and the other component reviews are present.
22. Upload test data to the repository. This will also create a new changeset revision.
23. Review the functional tests component on the repository, copying the other components from the previous review.
24. Verify that the functional tests component review has been updated, and as in step 21, the other reviews are unchanged.
25. Upload a new version of the tool.
26. Review the new revision's functional tests component.
27. Verify that the functional tests component review displays correctly.
"""
class TestRepositoryComponentReviews(ShedTwillTestCase):
"""Test repository component review features."""
def test_0000_initiate_users(self):
"""Create necessary user accounts and login as an admin user.
We are at step 1.
Create all the user accounts that are needed for this test script to run independently of other test.
Previously created accounts will not be re-created.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
test_user_1 = self.test_db_util.get_user(common.test_user_1_email)
assert (
test_user_1 is not None
), f"Problem retrieving user with email {common.test_user_1_email} from the database"
self.test_db_util.get_private_role(test_user_1)
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
test_user_2 = self.test_db_util.get_user(common.test_user_2_email)
assert (
test_user_2 is not None
), f"Problem retrieving user with email {common.test_user_2_email} from the database"
self.test_db_util.get_private_role(test_user_2)
self.login(email=common.admin_email, username=common.admin_username)
admin_user = self.test_db_util.get_user(common.admin_email)
assert admin_user is not None, f"Problem retrieving user with email {common.admin_email} from the database"
self.test_db_util.get_private_role(admin_user)
def test_0005_grant_reviewer_role(self):
"""Grant the repository reviewer role to test_user_2.
We are at step 2.
We now have an admin user (admin_user) and two non-admin users (test_user_1 and test_user_2). Grant the repository
reviewer role to test_user_2, who will not be the owner of the reviewed repositories.
"""
reviewer_role = self.test_db_util.get_role_by_name("Repository Reviewer")
test_user_2 = self.test_db_util.get_user(common.test_user_2_email)
self.grant_role_to_user(test_user_2, reviewer_role)
def test_0010_verify_repository_review_components(self):
"""Ensure that the required review components exist.
We are at step 3.
We now have an admin user (admin_user) and two non-admin users (test_user_1 and test_user_2). Grant the repository
reviewer role to test_user_2, who will not be the owner of the reviewed repositories.
"""
strings_not_displayed = ["Repository dependencies"]
self.manage_review_components(strings_not_displayed=strings_not_displayed)
self.add_repository_review_component(
name="Repository dependencies",
description="Repository dependencies defined in a file named repository_dependencies.xml included in the repository",
)
strings_displayed = [
"Data types",
"Functional tests",
"README",
"Repository dependencies",
"Tool dependencies",
"Tools",
"Workflows",
]
self.manage_review_components(strings_displayed=strings_displayed)
def test_0015_create_repository(self):
"""Create and populate the filtering repository
We are at step 4.
Log in as test_user_1 and create the filtering repository, then upload a basic set of
components to be reviewed in subsequent tests.
"""
category = self.create_category(
name="Test 0400 Repository Component Reviews", description="Test 0400 Repository Component Reviews"
)
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
strings_displayed = self.expect_repo_created_strings(repository_name)
repository = self.get_or_create_repository(
name=repository_name,
description=repository_description,
long_description=repository_long_description,
owner=common.test_user_1_name,
category_id=self.security.encode_id(category.id),
strings_displayed=strings_displayed,
)
self.upload_file(
repository,
filename="filtering/filtering_1.1.0.tar",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded filtering 1.1.0 tarball.",
strings_displayed=[],
strings_not_displayed=[],
)
def test_0020_review_initial_revision_data_types(self):
"""Review the datatypes component for the current tip revision.
We are at step 5.
Log in as test_user_2 and review the data types component of the filtering repository owned by test_user_1.
# Review this revision:
# Data types (N/A)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {"Data types": dict()}
self.create_repository_review(repository, review_contents_dict)
def test_0025_verify_datatype_review(self):
"""Verify that the datatypes component review displays correctly.
We are at step 6.
Log in as test_user_1 and check that the filtering repository only has a review for the data types component.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Data types", "not_applicable"]
strings_not_displayed = [
"Functional tests",
"README",
"Repository dependencies",
"Tool dependencies",
"Tools",
"Workflows",
]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0030_review_initial_revision_functional_tests(self):
"""Review the functional tests component for the current tip revision.
We are at step 7.
Log in as test_user_2 and review the functional tests component for this repository. Since the repository
has not been altered, this will update the existing review to add a component.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {
"Functional tests": dict(rating=1, comment="Functional tests missing", approved="no", private="yes")
}
self.review_repository(repository, review_contents_dict, user)
# def test_0030_verify_review_display( self ):
# """Verify that private reviews are restricted to owner and reviewer, and non-private views are viewable by others."""
# # Currently not implemented because third parties cannot view reviews whether they are private or not.
# self.login( email=common.test_user_3_email, username=common.test_user_3_name )
def test_0035_verify_functional_test_review(self):
"""Verify that the functional tests component review displays correctly.
We are at step 8.
Log in as test_user_1 and check that the filtering repository now has reviews
for the data types and functional tests components. Since the functional tests component was not marked as 'Not applicable',
also check for the review comment.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Functional tests", "Functional tests missing", "no"]
strings_not_displayed = ["README", "Repository dependencies", "Tool dependencies", "Tools", "Workflows"]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0040_review_readme(self):
"""Review the readme component for the current tip revision.
We are at step 9.
Log in as test_user_2 and update the review with the readme component marked as 'Not applicable'.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
# README (N/A)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {"README": dict()}
self.review_repository(repository, review_contents_dict, user)
def test_0045_verify_readme_review(self):
"""Verify that the readme component review displays correctly.
We are at step 10.
Log in as test_user_1 and verify that the repository component reviews now include a review for the readme component.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["README", "not_applicable"]
strings_not_displayed = ["Repository dependencies", "Tool dependencies", "Tools", "Workflows"]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0050_review_repository_dependencies(self):
"""Review the repository dependencies component for the current tip revision.
We are at step 11.
Log in as test_user_2 and update the review with the repository dependencies component marked as 'Not applicable'.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
# README (N/A)
# Repository dependencies (N/A)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {"Repository dependencies": dict()}
self.review_repository(repository, review_contents_dict, user)
def test_0055_verify_repository_dependency_review(self):
"""Verify that the repository dependencies component review displays correctly.
We are at step 12.
Log in as test_user_1 and verify that the repository component reviews now include a review
for the repository dependencies component.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Repository dependencies", "not_applicable"]
strings_not_displayed = ["Tool dependencies", "Tools", "Workflows"]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0060_review_tool_dependencies(self):
"""Review the tool dependencies component for the current tip revision.
We are at step 13.
Log in as test_user_2 and update the review with the tool dependencies component marked as 'Not applicable'.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
# README (N/A)
# Repository dependencies (N/A)
# Tool dependencies (N/A)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {"Tool dependencies": dict()}
self.review_repository(repository, review_contents_dict, user)
def test_0065_verify_tool_dependency_review(self):
"""Verify that the tool dependencies component review displays correctly.
We are at step 14.
Log in as test_user_1 and verify that the repository component reviews now include a review
for the tool dependencies component.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Tool dependencies", "not_applicable"]
strings_not_displayed = ["Tools", "Workflows"]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0070_review_tools(self):
"""Review the tools component for the current tip revision.
We are at step 15.
Log in as test_user_2 and update the review with the tools component given
a favorable review, with 5 stars, and approved status.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
# README (N/A)
# Repository dependencies (N/A)
# Tool dependencies (N/A)
# Tools (5 stars, good review)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {
"Tools": dict(rating=5, comment="Excellent tool, easy to use.", approved="yes", private="no")
}
self.review_repository(repository, review_contents_dict, user)
def test_0075_verify_tools_review(self):
"""Verify that the tools component review displays correctly.
We are at step 16.
Log in as test_user_1 and verify that the repository component reviews now include a review
for the tools component. As before, check for the presence of the comment on this review.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Tools", "yes", "Excellent tool, easy to use."]
strings_not_displayed = ["Workflows"]
self.verify_repository_reviews(
repository, reviewer=user, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed
)
def test_0080_review_workflows(self):
"""Review the workflows component for the current tip revision.
We are at step 17.
Log in as test_user_2 and update the review with the workflows component marked as 'Not applicable'.
# Review this revision:
# Data types (N/A)
# Functional tests (One star, comment 'functional tests missing')
# README (N/A)
# Repository dependencies (N/A)
# Tool dependencies (N/A)
# Tools (5 stars, good review)
# Workflows (N/A)
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {"Workflows": dict()}
self.review_repository(repository, review_contents_dict, user)
def test_0085_verify_workflows_review(self):
"""Verify that the workflows component review displays correctly.
We are at step 18.
Log in as test_user_1 and verify that the repository component reviews now include a review
for the workflows component.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Workflows", "not_applicable"]
self.verify_repository_reviews(repository, reviewer=user, strings_displayed=strings_displayed)
def test_0090_upload_readme_file(self):
"""Upload a readme file to the filtering repository.
We are at step 19.
Log in as test_user_1, the repository owner, and upload readme.txt to the repository. This will create
a new changeset revision for this repository, which will need to be reviewed.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
self.upload_file(
repository,
filename="readme.txt",
filepath=None,
valid_tools_only=True,
uncompress_file=False,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded readme.txt.",
strings_displayed=[],
strings_not_displayed=[],
)
def test_0095_review_new_changeset_readme_component(self):
"""Update the filtering repository's readme component review to reflect the presence of the readme file.
We are at step 20.
There is now a new changeset revision in the repository's changelog, but it has no review associated with it.
Get the previously reviewed changeset hash, and pass that and the review id to the create_repository_review
method, in order to copy the previous review's contents. Then update the new review to reflect the presence of
a readme file.
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# Get the last changeset revision that has a review associated with it.
last_review = self.get_last_reviewed_revision_by_user(user, repository)
if last_review is None:
raise AssertionError("Previous review expected, none found.")
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {
"README": dict(
rating=5,
comment="Clear and concise readme file, a true pleasure to read.",
approved="yes",
private="no",
)
}
self.create_repository_review(
repository,
review_contents_dict,
changeset_revision=self.get_repository_tip(repository),
copy_from=(str(last_review.changeset_revision), last_review.id),
)
def test_0100_verify_readme_review(self):
"""Verify that the readme component review displays correctly.
We are at step 21.
Log in as the repository owner (test_user_1) and check the repository component reviews to
verify that the readme component is now reviewed and approved.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["README", "yes", "Clear and concise readme file, a true pleasure to read."]
self.verify_repository_reviews(repository, reviewer=user, strings_displayed=strings_displayed)
def test_0105_upload_test_data(self):
"""Upload the missing test data to the filtering repository.
We are at step 22.
Remain logged in as test_user_1 and upload test data to the repository. This will also create a
new changeset revision that needs to be reviewed. This will replace the changeset hash associated with
the last dowloadable revision, but the last repository review will still be associated with the
last dowloadable revision hash.
"""
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
self.upload_file(
repository,
filename="filtering/filtering_test_data.tar",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded filtering test data.",
strings_displayed=[],
strings_not_displayed=[],
)
def test_0110_review_new_changeset_functional_tests(self):
"""Update the filtering repository's readme component review to reflect the presence of the readme file.
We are at step 23.
Log in as test_user_2 and get the last reviewed changeset hash, and pass that and the review id to
the create_repository_review method, then update the copied review to approve the functional tests
component.
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
# Get the changeset immediately prior to the tip, and pass it to the create review method.
last_review = self.get_last_reviewed_revision_by_user(user, repository)
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {
"Functional tests": dict(rating=5, comment="A good set of functional tests.", approved="yes", private="no")
}
self.create_repository_review(
repository,
review_contents_dict,
changeset_revision=self.get_repository_tip(repository),
copy_from=(str(last_review.changeset_revision), last_review.id),
)
def test_0115_verify_functional_tests_review(self):
"""Verify that the functional tests component review displays correctly.
We are at step 24.
Log in as the repository owner, test_user_1, and verify that the new revision's functional tests component
review has been updated with an approved status and favorable comment.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = ["Functional tests", "yes", "A good set of functional tests."]
self.verify_repository_reviews(repository, reviewer=user, strings_displayed=strings_displayed)
def test_0120_upload_new_tool_version(self):
"""Upload filtering 2.2.0 to the filtering repository.
We are at step 25.
Log in as test_user_1 and upload a new version of the tool to the filtering repository. This will create
a new downloadable revision, with no associated repository component reviews.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
self.upload_file(
repository,
filename="filtering/filtering_2.2.0.tar",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded filtering 2.2.0 tarball.",
strings_displayed=[],
strings_not_displayed=[],
)
def test_0125_review_new_changeset_functional_tests(self):
"""Update the filtering repository's review to apply to the new changeset with filtering 2.2.0.
We are at step 26.
Log in as test_user_2 and copy the last review for this repository to the new changeset. Then
update the tools component review to refer to the new tool version.
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
last_review = self.get_last_reviewed_revision_by_user(user, repository)
# Something needs to change so that the review will save.
# The create_repository_review method takes a dict( component label=review contents ).
# If review_contents is empty, it marks that component as not applicable. The review
# contents dict should have the structure:
# {
# rating: 1-5,
# comment: <text>
# approved: yes/no
# private: yes/no
# }
review_contents_dict = {
"Tools": dict(
rating=5,
comment="Version 2.2.0 does the impossible and improves this tool.",
approved="yes",
private="yes",
)
}
self.create_repository_review(
repository,
review_contents_dict,
changeset_revision=self.get_repository_tip(repository),
copy_from=(str(last_review.changeset_revision), last_review.id),
)
def test_0135_verify_review_for_new_version(self):
"""Verify that the reviews display correctly for this changeset revision.
We are at step 27.
Log in as test_user_1 and check that the tools component review is for filtering 2.2.0, but that the other component
reviews had their contents copied from the last reviewed changeset.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = [
"Data types",
"Functional tests",
"yes",
"A good set of functional tests.",
"README",
"yes",
"Workflows",
"Tools",
]
strings_displayed.extend(
["Clear and concise readme file, a true pleasure to read.", "Tool dependencies", "not_applicable"]
)
strings_displayed.extend(
["Repository dependencies", "Version 2.2.0 does the impossible and improves this tool."]
)
self.verify_repository_reviews(repository, reviewer=user, strings_displayed=strings_displayed)
@@ -1,246 +0,0 @@
from ..base.twilltestcase import (
common,
ShedTwillTestCase,
)
repository_name = "filtering_0410"
repository_description = "Galaxy filtering tool for test 0410"
repository_long_description = "Long description of Galaxy filtering tool for test 0410"
"""
1. Create a repository in the tool shed owned by test_user_1.
2. Have test_user_2 complete a review of the repository.
3. Have test_user_1 browse the review.
4. Have test_user_3 browse the repository and make sure they are not allowed to browse the review.
5. Have test_user_1 give write permission on the repository to the test_user_3.
6. Have test_user_3 browse the repository again and they should now have the ability to browse the review.
7. Have test_user_3 browse the review.
"""
class TestRepositoryComponentReviews(ShedTwillTestCase):
"""Test repository component review features."""
def test_0000_initiate_users(self):
"""Create necessary user accounts and login as an admin user.
Create all the user accounts that are needed for this test script to run independently of other test.
Previously created accounts will not be re-created.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
test_user_1 = self.test_db_util.get_user(common.test_user_1_email)
assert (
test_user_1 is not None
), f"Problem retrieving user with email {common.test_user_1_email} from the database"
self.test_db_util.get_private_role(test_user_1)
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
test_user_2 = self.test_db_util.get_user(common.test_user_2_email)
assert (
test_user_2 is not None
), f"Problem retrieving user with email {common.test_user_2_email} from the database"
self.test_db_util.get_private_role(test_user_2)
self.login(email=common.test_user_3_email, username=common.test_user_3_name)
test_user_3 = self.test_db_util.get_user(common.test_user_3_email)
assert (
test_user_3 is not None
), f"Problem retrieving user with email {common.test_user_3_email} from the database"
self.test_db_util.get_private_role(test_user_3)
self.login(email=common.admin_email, username=common.admin_username)
admin_user = self.test_db_util.get_user(common.admin_email)
assert admin_user is not None, f"Problem retrieving user with email {common.admin_email} from the database"
self.test_db_util.get_private_role(admin_user)
def test_0005_grant_reviewer_role(self):
"""Grant the repository reviewer role to test_user_2.
We now have an admin user (admin_user) and three non-admin users (test_user_1, test_user_2, and test_user_3). Grant the repository
reviewer role to test_user_2, who will not be the owner of the reviewed repositories, and do not grant any roles to test_user_3 yet.
"""
reviewer_role = self.test_db_util.get_role_by_name("Repository Reviewer")
test_user_2 = self.test_db_util.get_user(common.test_user_2_email)
self.grant_role_to_user(test_user_2, reviewer_role)
def test_0010_verify_repository_review_components(self):
"""Ensure that the required review components exist.
Make sure all the components we are to review are recorded in the database.
"""
self.add_repository_review_component(
name="Repository dependencies",
description="Repository dependencies defined in a file named repository_dependencies.xml included in the repository",
)
strings_displayed = [
"Data types",
"Functional tests",
"README",
"Repository dependencies",
"Tool dependencies",
"Tools",
"Workflows",
]
self.manage_review_components(strings_displayed=strings_displayed)
def test_0015_create_repository(self):
"""Create and populate the filtering repository
We are at step 1.
Log in as test_user_1 and create the filtering repository, then upload a basic set of
components to be reviewed in subsequent tests.
"""
category = self.create_category(
name="Test 0400 Repository Component Reviews", description="Test 0400 Repository Component Reviews"
)
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
strings_displayed = self.expect_repo_created_strings(repository_name)
repository = self.get_or_create_repository(
name=repository_name,
description=repository_description,
long_description=repository_long_description,
owner=common.test_user_1_name,
category_id=self.security.encode_id(category.id),
strings_displayed=strings_displayed,
)
self.upload_file(
repository,
filename="filtering/filtering_1.1.0.tar",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded filtering 1.1.0 tarball.",
strings_displayed=[],
strings_not_displayed=[],
)
self.upload_file(
repository,
filename="filtering/filtering_test_data.tar",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded filtering test data.",
strings_displayed=[],
strings_not_displayed=[],
)
self.upload_file(
repository,
filename="readme.txt",
filepath=None,
valid_tools_only=True,
uncompress_file=True,
remove_repo_files_not_in_tar=False,
commit_message="Uploaded readme.txt.",
strings_displayed=[],
strings_not_displayed=[],
)
def test_0020_review_repository(self):
"""Complete a review of the filtering repository.
We are at step 2 - Have test_user_2 complete a review of the repository.
Review all components of the filtering repository, with the appropriate contents and approved/not approved/not applicable status.
"""
self.login(email=common.test_user_2_email, username=common.test_user_2_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
review_contents_dict = {
"Data types": dict(),
"README": dict(
rating=5,
comment="Clear and concise readme file, a true pleasure to read.",
approved="yes",
private="no",
),
"Functional tests": dict(rating=5, comment="A good set of functional tests.", approved="yes", private="no"),
"Repository dependencies": dict(),
"Tool dependencies": dict(),
"Tools": dict(rating=5, comment="Excellent tool, easy to use.", approved="yes", private="no"),
"Workflows": dict(),
}
self.create_repository_review(repository, review_contents_dict)
def test_0025_verify_repository_review(self):
"""Verify that the review was completed and displays properly.
We are at step 3 - Have test_user_1 browse the review.
Verify that all the review components were submitted, and that the repository owner can see the review.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = [
"Data types",
"Functional tests",
"yes",
"A good set of functional tests.",
"README",
"yes",
"Workflows",
"Tools",
]
strings_displayed.extend(
["Clear and concise readme file, a true pleasure to read.", "Tool dependencies", "not_applicable"]
)
strings_displayed.extend(["Repository dependencies", "Excellent tool, easy to use."])
strings_displayed = ["Browse reviews of this repository"]
self.display_manage_repository_page(repository, strings_displayed=strings_displayed)
self.verify_repository_reviews(repository, reviewer=user, strings_displayed=strings_displayed)
def test_0030_browse_with_other_user(self):
"""Verify that test_user_3 is blocked from browsing the review.
We are at step 4 - Have test_user_3 browse the repository and make sure they are not allowed to browse the review.
"""
self.login(email=common.test_user_3_email, username=common.test_user_3_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_not_displayed = ["Browse reviews of this repository"]
self.display_manage_repository_page(repository, strings_not_displayed=strings_not_displayed)
strings_not_displayed = [
"A good set of functional tests.",
"Clear and concise readme file, a true pleasure to read.",
]
strings_not_displayed.append("Excellent tool, easy to use.")
changeset_revision = self.get_repository_tip(repository)
review = self.test_db_util.get_repository_review_by_user_id_changeset_revision(
user.id, repository.id, changeset_revision
)
self.browse_component_review(review, strings_not_displayed=strings_not_displayed)
def test_0035_grant_write_access_to_other_user(self):
"""Grant write access on the filtering_0410 repository to test_user_3.
We are at step 5 - Have test_user_1 give write permission on the repository to the test_user_3.
"""
self.login(email=common.test_user_1_email, username=common.test_user_1_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
self.grant_write_access(repository, usernames=[common.test_user_3_name])
def test_0040_verify_test_user_3_can_browse_reviews(self):
"""Check that test_user_3 can now browse reviews.
We are at step 6 - Have test_user_3 browse the repository again and they should now have the ability to browse the review.
"""
self.login(email=common.test_user_3_email, username=common.test_user_3_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
strings_displayed = ["Browse reviews of this repository"]
self.display_manage_repository_page(repository, strings_displayed=strings_displayed)
def test_0045_verify_browse_review_with_write_access(self):
"""Check that test_user_3 can now display reviews.
We are at step 7 - Have test_user_3 browse the review.
"""
self.login(email=common.test_user_3_email, username=common.test_user_3_name)
repository = self.test_db_util.get_repository_by_name_and_owner(repository_name, common.test_user_1_name)
user = self.test_db_util.get_user(common.test_user_2_email)
strings_displayed = [
"A&nbsp;good&nbsp;set&nbsp;of&nbsp;functional&nbsp;tests.",
"Clear&nbsp;and&nbsp;concise&nbsp;readme&nbsp;file",
"a&nbsp;true&nbsp;pleasure&nbsp;to&nbsp;read.",
"Excellent&nbsp;tool,&nbsp;easy&nbsp;to&nbsp;use.",
]
changeset_revision = self.get_repository_tip(repository)
review = self.test_db_util.get_repository_review_by_user_id_changeset_revision(
user.id, repository.id, changeset_revision
)
self.browse_component_review(review, strings_displayed=strings_displayed)
-21
View File
@@ -272,27 +272,6 @@ def get_repository_metadata_by_repository_id_changeset_revision(app, id, changes
return get_repository_metadata_by_changeset_revision(app, id, changeset_revision)
def get_repository_metadata_revisions_for_review(repository, reviewed=True):
repository_metadata_revisions = []
metadata_changeset_revision_hashes = []
if reviewed:
for metadata_revision in repository.metadata_revisions:
metadata_changeset_revision_hashes.append(metadata_revision.changeset_revision)
for review in repository.reviews:
if review.changeset_revision in metadata_changeset_revision_hashes:
rmcr_hashes = [rmr.changeset_revision for rmr in repository_metadata_revisions]
if review.changeset_revision not in rmcr_hashes:
repository_metadata_revisions.append(review.repository_metadata)
else:
for review in repository.reviews:
if review.changeset_revision not in metadata_changeset_revision_hashes:
metadata_changeset_revision_hashes.append(review.changeset_revision)
for metadata_revision in repository.metadata_revisions:
if metadata_revision.changeset_revision not in metadata_changeset_revision_hashes:
repository_metadata_revisions.append(metadata_revision)
return repository_metadata_revisions
def get_updated_changeset_revisions(app, name, owner, changeset_revision):
"""
Return a string of comma-separated changeset revision hashes for all available updates to the received changeset
-143
View File
@@ -1,143 +0,0 @@
import logging
from sqlalchemy import and_
from tool_shed.util import hg_util
log = logging.getLogger(__name__)
def can_browse_repository_reviews(app, user, repository):
"""
Determine if there are any reviews of the received repository for which the
current user has permission to browse any component reviews.
"""
if user:
for review in repository.reviews:
for component_review in review.component_reviews:
if app.security_agent.user_can_browse_component_review(app, repository, component_review, user):
return True
return False
def changeset_revision_reviewed_by_user(user, repository, changeset_revision):
"""Determine if the current changeset revision has been reviewed by the current user."""
for review in repository.reviews:
if review.changeset_revision == changeset_revision and review.user == user:
return True
return False
def get_component(app, id):
"""Get a component from the database."""
sa_session = app.model.session
return sa_session.query(app.model.Component).get(app.security.decode_id(id))
def get_component_review(app, id):
"""Get a component_review from the database"""
sa_session = app.model.session
return sa_session.query(app.model.ComponentReview).get(app.security.decode_id(id))
def get_component_by_name(app, name):
"""Get a component from the database via a name."""
sa_session = app.model.session
return sa_session.query(app.model.Component).filter(app.model.Component.table.c.name == name).first()
def get_component_review_by_repository_review_id_component_id(app, repository_review_id, component_id):
"""Get a component_review from the database via repository_review_id and component_id."""
sa_session = app.model.session
return (
sa_session.query(app.model.ComponentReview)
.filter(
and_(
app.model.ComponentReview.table.c.repository_review_id == app.security.decode_id(repository_review_id),
app.model.ComponentReview.table.c.component_id == app.security.decode_id(component_id),
)
)
.first()
)
def get_components(app):
sa_session = app.model.session
return sa_session.query(app.model.Component).order_by(app.model.Component.name).all()
def get_previous_repository_reviews(app, repository, changeset_revision):
"""
Return an ordered dictionary of repository reviews up to and including the
received changeset revision.
"""
repo = repository.hg_repo
reviewed_revision_hashes = [review.changeset_revision for review in repository.reviews]
previous_reviews_dict = {}
for changeset in hg_util.reversed_upper_bounded_changelog(repo, changeset_revision):
previous_changeset_revision = str(repo[changeset])
if previous_changeset_revision in reviewed_revision_hashes:
previous_rev, previous_changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(
repo, previous_changeset_revision
)
revision_reviews = get_reviews_by_repository_id_changeset_revision(
app, app.security.encode_id(repository.id), previous_changeset_revision
)
previous_reviews_dict[previous_changeset_revision] = dict(
changeset_revision_label=previous_changeset_revision_label, reviews=revision_reviews
)
return previous_reviews_dict
def get_review(app, id):
"""Get a repository_review from the database via id."""
sa_session = app.model.session
return sa_session.query(app.model.RepositoryReview).get(app.security.decode_id(id))
def get_review_by_repository_id_changeset_revision_user_id(app, repository_id, changeset_revision, user_id):
"""
Get a repository_review from the database via repository id, changeset_revision
and user_id.
"""
sa_session = app.model.session
return (
sa_session.query(app.model.RepositoryReview)
.filter(
and_(
app.model.RepositoryReview.repository_id == app.security.decode_id(repository_id),
app.model.RepositoryReview.changeset_revision == changeset_revision,
app.model.RepositoryReview.user_id == app.security.decode_id(user_id),
)
)
.first()
)
def get_reviews_by_repository_id_changeset_revision(app, repository_id, changeset_revision):
"""Get all repository_reviews from the database via repository id and changeset_revision."""
sa_session = app.model.session
return (
sa_session.query(app.model.RepositoryReview)
.filter(
and_(
app.model.RepositoryReview.repository_id == app.security.decode_id(repository_id),
app.model.RepositoryReview.changeset_revision == changeset_revision,
)
)
.all()
)
def has_previous_repository_reviews(app, repository, changeset_revision):
"""
Determine if a repository has a changeset revision review prior to the
received changeset revision.
"""
repo = repository.hg_repo
reviewed_revision_hashes = [review.changeset_revision for review in repository.reviews]
for changeset in hg_util.reversed_upper_bounded_changelog(repo, changeset_revision):
previous_changeset_revision = str(repo[changeset])
if previous_changeset_revision in reviewed_revision_hashes:
return True
return False
+1 -7
View File
@@ -123,12 +123,6 @@ def get_repos(sa_session, file_path, hgweb_config_dir, **kwargs):
user = sa_session.query(model.User).filter(model.User.id == repo.user_id).one()
repo_owner_username = user.username.lower()
approved = "no"
for review in repo.reviews:
if review.approved == "yes":
approved = "yes"
break
last_updated = pretty_print_time_interval(repo.update_time)
full_last_updated = repo.update_time.strftime("%Y-%m-%d %I:%M %p")
@@ -165,7 +159,7 @@ def get_repos(sa_session, file_path, hgweb_config_dir, **kwargs):
remote_repository_url=unicodify(remote_repository_url),
repo_owner_username=unicodify(repo_owner_username),
times_downloaded=unicodify(times_downloaded),
approved=unicodify(approved),
approved=unicodify("no"),
last_updated=unicodify(last_updated),
full_last_updated=unicodify(full_last_updated),
tools_list=tools_list,
-10
View File
@@ -125,15 +125,7 @@ class GroupsController(BaseAPIController):
time_repo_updated_full = repo.update_time.strftime("%Y-%m-%d %I:%M %p")
time_repo_created = pretty_print_time_interval(repo.create_time, True)
time_repo_updated = pretty_print_time_interval(repo.update_time, True)
approved = ""
ratings = []
for review in repo.reviews:
if review.rating:
ratings.append(review.rating)
if review.approved == "yes":
approved = "yes"
# TODO add user ratings
ratings_mean = str(float(sum(ratings)) / len(ratings)) if len(ratings) > 0 else ""
total_downloads += repo.times_downloaded
group_repos.append(
{
@@ -145,8 +137,6 @@ class GroupsController(BaseAPIController):
"time_updated_full": time_repo_updated_full,
"time_updated": time_repo_updated,
"description": repo.description,
"approved": approved,
"ratings_mean": ratings_mean,
"categories": categories,
}
)
@@ -263,10 +263,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
return trans.response.send_redirect(
web.url_for(controller="repository", action="browse_repositories_by_user", **kwd)
)
elif operation == "reviewed_repositories_i_own":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="reviewed_repositories_i_own")
)
elif operation == "repositories_by_category":
category_id = kwd.get("id", None)
message = escape(kwd.get("message", ""))
@@ -1632,14 +1628,8 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
# TODO: move the following to some in-memory register so these queries can be done once
# at startup. The in-memory register can then be managed during the current session.
can_administer_repositories = False
has_reviewed_repositories = False
has_deprecated_repositories = False
if current_user:
# See if the current user owns any repositories that have been reviewed.
for repository in current_user.active_repositories:
if repository.reviews:
has_reviewed_repositories = True
break
# See if the current user has any repositories that have been marked as deprecated.
for repository in current_user.active_repositories:
if repository.deprecated:
@@ -1666,7 +1656,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
"/webapps/tool_shed/index.mako",
repository_metadata=repository_metadata,
can_administer_repositories=can_administer_repositories,
has_reviewed_repositories=has_reviewed_repositories,
has_deprecated_repositories=has_deprecated_repositories,
user_id=user_id,
repository_id=repository_id,
@@ -1822,7 +1811,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
description = kwd.get("description", repository.description)
long_description = kwd.get("long_description", repository.long_description)
avg_rating, num_ratings = self.get_ave_item_rating_data(trans.sa_session, repository, webapp_model=trans.model)
display_reviews = util.string_as_bool(kwd.get("display_reviews", False))
alerts = kwd.get("alerts", "")
alerts_checked = CheckboxField.is_checked(alerts)
category_ids = util.listify(kwd.get("category_id", ""))
@@ -2016,7 +2004,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
categories=categories,
metadata=metadata,
avg_rating=avg_rating,
display_reviews=display_reviews,
num_ratings=num_ratings,
alerts_check_box=alerts_check_box,
malicious_check_box=malicious_check_box,
@@ -2074,13 +2061,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
status=status,
)
@web.expose
@require_login("review repository revision")
def manage_repository_reviews_of_revision(self, trans, **kwd):
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repository_reviews_of_revision", **kwd)
)
@web.expose
@require_login("multi select email alerts")
def multi_select_email_alerts(self, trans, **kwd):
@@ -2268,7 +2248,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
comment = kwd.get("comment", "")
rating = self.rate_item(trans, trans.user, repository, rating, comment)
avg_rating, num_ratings = self.get_ave_item_rating_data(trans.sa_session, repository, webapp_model=trans.model)
display_reviews = util.string_as_bool(kwd.get("display_reviews", False))
rra = self.get_user_item_rating(trans.sa_session, trans.user, repository, webapp_model=trans.model)
metadata = metadata_util.get_repository_metadata_by_repository_id_changeset_revision(
trans.app, id, changeset_revision, metadata_only=True
@@ -2281,7 +2260,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
metadata=metadata,
revision_label=revision_label,
avg_rating=avg_rating,
display_reviews=display_reviews,
num_ratings=num_ratings,
rra=rra,
repository_type_select_field=repository_type_select_field,
@@ -2763,7 +2741,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
repository, changeset_revision=changeset_revision
)
repository.clone_url = common_util.generate_clone_url_for_repository_in_tool_shed(trans.user, repository)
display_reviews = kwd.get("display_reviews", False)
alerts = kwd.get("alerts", "")
alerts_checked = CheckboxField.is_checked(alerts)
if repository.email_alerts:
@@ -2833,7 +2810,6 @@ class RepositoryController(BaseUIController, ratings_util.ItemRatings):
metadata=metadata,
containers_dict=containers_dict,
avg_rating=avg_rating,
display_reviews=display_reviews,
num_ratings=num_ratings,
alerts_check_box=alerts_check_box,
changeset_revision=changeset_revision,
@@ -1,670 +0,0 @@
import logging
from sqlalchemy import (
and_,
false,
func,
)
import tool_shed.grids.repository_review_grids as repository_review_grids
import tool_shed.grids.util as grids_util
from galaxy import (
util,
web,
)
from galaxy.web.form_builder import CheckboxField
from galaxy.webapps.base.controller import BaseUIController
from tool_shed.util import (
hg_util,
metadata_util,
repository_util,
review_util,
shed_util_common as suc,
)
from tool_shed.util.container_util import STRSEP
from tool_shed.util.web_util import escape
from tool_shed.webapp.framework.decorators import require_login
from tool_shed.webapp.util import ratings_util
log = logging.getLogger(__name__)
class RepositoryReviewController(BaseUIController, ratings_util.ItemRatings):
component_grid = repository_review_grids.ComponentGrid()
repositories_ready_for_review_grid = repository_review_grids.RepositoriesReadyForReviewGrid()
repositories_reviewed_by_me_grid = repository_review_grids.RepositoriesReviewedByMeGrid()
repositories_with_reviews_grid = repository_review_grids.RepositoriesWithReviewsGrid()
repositories_without_reviews_grid = repository_review_grids.RepositoriesWithoutReviewsGrid()
repository_reviews_by_user_grid = repository_review_grids.RepositoryReviewsByUserGrid()
reviewed_repositories_i_own_grid = repository_review_grids.ReviewedRepositoriesIOwnGrid()
repositories_with_no_tool_tests_grid = repository_review_grids.RepositoriesWithNoToolTestsGrid()
@web.expose
@require_login("approve repository review")
def approve_repository_review(self, trans, **kwd):
# The value of the received id is the encoded review id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
encoded_review_id = kwd["id"]
review = review_util.get_review(trans.app, encoded_review_id)
if kwd.get("approve_repository_review_button", False):
approved_select_field_name = f"{encoded_review_id}{STRSEP}approved"
approved_select_field_value = str(kwd[approved_select_field_name])
review.approved = approved_select_field_value
trans.sa_session.add(review)
trans.sa_session.flush()
message = f"Approved value <b>{escape(approved_select_field_value)}</b> saved for this revision."
repository_id = trans.security.encode_id(review.repository_id)
changeset_revision = review.changeset_revision
return trans.response.send_redirect(
web.url_for(
controller="repository_review",
action="manage_repository_reviews_of_revision",
id=repository_id,
changeset_revision=changeset_revision,
message=message,
status=status,
)
)
@web.expose
@require_login("browse components")
def browse_components(self, trans, **kwd):
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "create":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="create_component", **kwd)
)
return self.component_grid(trans, **kwd)
@web.expose
@require_login("browse review")
def browse_review(self, trans, **kwd):
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
review = review_util.get_review(trans.app, kwd["id"])
repository = review.repository
repo = repository.hg_repo
rev, changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(repo, review.changeset_revision)
return trans.fill_template(
"/webapps/tool_shed/repository_review/browse_review.mako",
repository=repository,
changeset_revision_label=changeset_revision_label,
review=review,
message=message,
status=status,
)
def copy_review(self, trans, review_to_copy, review):
for component_review in review_to_copy.component_reviews:
copied_component_review = trans.model.ComponentReview(
repository_review_id=review.id,
component_id=component_review.component.id,
comment=component_review.comment,
private=component_review.private,
approved=component_review.approved,
rating=component_review.rating,
)
trans.sa_session.add(copied_component_review)
trans.sa_session.flush()
review.approved = review_to_copy.approved
review.rating = review_to_copy.rating
trans.sa_session.add(review)
trans.sa_session.flush()
@web.expose
@require_login("create component")
def create_component(self, trans, **kwd):
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
name = kwd.get("name", "")
description = kwd.get("description", "")
if kwd.get("create_component_button", False):
if not name or not description:
message = "Enter a valid name and a description"
status = "error"
elif review_util.get_component_by_name(trans.app, name):
message = "A component with that name already exists"
status = "error"
else:
component = trans.app.model.Component(name=name, description=description)
trans.sa_session.add(component)
trans.sa_session.flush()
message = f"Component '{escape(component.name)}' has been created"
status = "done"
trans.response.send_redirect(
web.url_for(
controller="repository_review", action="manage_components", message=message, status=status
)
)
return trans.fill_template(
"/webapps/tool_shed/repository_review/create_component.mako",
name=name,
description=description,
message=message,
status=status,
)
@web.expose
@require_login("create review")
def create_review(self, trans, **kwd):
# The value of the received id is the encoded repository id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
repository_id = kwd.get("id", None)
changeset_revision = kwd.get("changeset_revision", None)
previous_review_id = kwd.get("previous_review_id", None)
create_without_copying = "create_without_copying" in kwd
if repository_id:
if changeset_revision:
# Make sure there is not already a review of the revision by the user.
repository = repository_util.get_repository_in_tool_shed(trans.app, repository_id)
if review_util.get_review_by_repository_id_changeset_revision_user_id(
app=trans.app,
repository_id=repository_id,
changeset_revision=changeset_revision,
user_id=trans.security.encode_id(trans.user.id),
):
message = f"You have already created a review for revision <b>{changeset_revision}</b> of repository <b>{escape(repository.name)}</b>."
status = "error"
else:
# See if there are any reviews for previous changeset revisions that the user can copy.
if (
not create_without_copying
and not previous_review_id
and review_util.has_previous_repository_reviews(trans.app, repository, changeset_revision)
):
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="select_previous_review", **kwd)
)
# A review can be initially performed only on an installable revision of a repository, so make sure we have metadata associated
# with the received changeset_revision.
repository_metadata = metadata_util.get_repository_metadata_by_changeset_revision(
trans.app, repository_id, changeset_revision
)
if repository_metadata:
metadata = repository_metadata.metadata
if metadata:
review = trans.app.model.RepositoryReview(
repository_id=repository_metadata.repository_id,
changeset_revision=changeset_revision,
user_id=trans.user.id,
rating=None,
deleted=False,
)
trans.sa_session.add(review)
trans.sa_session.flush()
if previous_review_id:
review_to_copy = review_util.get_review(trans.app, previous_review_id)
self.copy_review(trans, review_to_copy, review)
review_id = trans.security.encode_id(review.id)
message = f"Begin your review of revision <b>{changeset_revision}</b> of repository <b>{repository.name}</b>."
status = "done"
trans.response.send_redirect(
web.url_for(
controller="repository_review",
action="edit_review",
id=review_id,
message=message,
status=status,
)
)
else:
message = (
"A new review cannot be created for revision <b>%s</b> of repository <b>%s</b>. Select a valid revision and try again."
% (changeset_revision, escape(repository.name))
)
kwd["message"] = message
kwd["status"] = "error"
else:
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repository_reviews", **kwd)
)
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
@web.expose
@require_login("edit component")
def edit_component(self, trans, **kwd):
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
id = kwd.get("id", None)
if not id:
message = "No component ids received for editing"
trans.response.send_redirect(
web.url_for(controller="admin", action="manage_categories", message=message, status="error")
)
component = review_util.get_component(trans.app, id)
if kwd.get("edit_component_button", False):
new_description = kwd.get("description", "").strip()
if component.description != new_description:
component.description = new_description
trans.sa_session.add(component)
trans.sa_session.flush()
message = f"The information has been saved for the component named <b>{escape(component.name)}</b>"
status = "done"
return trans.response.send_redirect(
web.url_for(
controller="repository_review", action="manage_components", message=message, status=status
)
)
return trans.fill_template(
"/webapps/tool_shed/repository_review/edit_component.mako",
component=component,
message=message,
status=status,
)
@web.expose
@require_login("edit review")
def edit_review(self, trans, **kwd):
# The value of the received id is the encoded review id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
review_id = kwd.get("id", None)
review = review_util.get_review(trans.app, review_id)
components_dict = {}
for component in review_util.get_components(trans.app):
components_dict[component.name] = dict(component=component, component_review=None)
repository = review.repository
repo = repository.hg_repo
for component_review in review.component_reviews:
if component_review and component_review.component:
component_name = component_review.component.name
if component_name in components_dict:
component_review_dict = components_dict[component_name]
component_review_dict["component_review"] = component_review
components_dict[component_name] = component_review_dict
# Handle a Save button click.
save_button_clicked = False
save_buttons = [f"{comp_name}{STRSEP}review_button" for comp_name in components_dict.keys()]
save_buttons.append("revision_approved_button")
for save_button in save_buttons:
if save_button in kwd:
save_button_clicked = True
break
if save_button_clicked:
# Handle the revision_approved_select_field value.
revision_approved = kwd.get("revision_approved", None)
revision_approved_setting_changed = False
if revision_approved:
revision_approved = str(revision_approved)
if review.approved != revision_approved:
revision_approved_setting_changed = True
review.approved = revision_approved
trans.sa_session.add(review)
trans.sa_session.flush()
saved_component_names = []
for component_name in components_dict.keys():
flushed = False
# Retrieve the review information from the form.
# The star rating form field is a radio button list, so it will not be received if it was not clicked in the form.
# Due to this behavior, default the value to 0.
rating = 0
private = False
for k, v in kwd.items():
if k.startswith(f"{component_name}{STRSEP}"):
component_review_attr = k.replace(f"{component_name}{STRSEP}", "")
if component_review_attr == "component_id":
component_id = str(v)
elif component_review_attr == "comment":
comment = str(v)
elif component_review_attr == "private":
private = CheckboxField.is_checked(v)
elif component_review_attr == "approved":
approved = str(v)
elif component_review_attr == "rating":
rating = int(str(v))
component = review_util.get_component(trans.app, component_id)
component_review = review_util.get_component_review_by_repository_review_id_component_id(
trans.app, review_id, component_id
)
if component_review:
# See if the existing component review should be updated.
if (
component_review.comment != comment
or component_review.private != private
or component_review.approved != approved
or component_review.rating != rating
):
component_review.comment = comment
component_review.private = private
component_review.approved = approved
component_review.rating = rating
trans.sa_session.add(component_review)
trans.sa_session.flush()
flushed = True
saved_component_names.append(component_name)
else:
# See if a new component_review should be created.
if comment or private or approved != trans.model.ComponentReview.approved_states.NO or rating:
component_review = trans.model.ComponentReview(
repository_review_id=review.id,
component_id=component.id,
comment=comment,
approved=approved,
rating=rating,
)
trans.sa_session.add(component_review)
trans.sa_session.flush()
flushed = True
saved_component_names.append(component_name)
if flushed:
# Update the repository rating value to be the average of all component review ratings.
average_rating = (
trans.sa_session.query(func.avg(trans.model.ComponentReview.table.c.rating))
.filter(
and_(
trans.model.ComponentReview.table.c.repository_review_id == review.id,
trans.model.ComponentReview.table.c.deleted == false(),
trans.model.ComponentReview.table.c.approved
!= trans.model.ComponentReview.approved_states.NA,
)
)
.scalar()
)
if average_rating is not None:
review.rating = int(average_rating)
trans.sa_session.add(review)
trans.sa_session.flush()
# Update the information in components_dict.
if component_name in components_dict:
component_review_dict = components_dict[component_name]
component_review_dict["component_review"] = component_review
components_dict[component_name] = component_review_dict
if revision_approved_setting_changed:
message += f"Approved value <b>{review.approved}</b> saved for this revision.<br/>"
if saved_component_names:
message += f"Reviews were saved for components: {', '.join(saved_component_names)}"
if not revision_approved_setting_changed and not saved_component_names:
message += "No changes were made to this review, so nothing was saved."
if review and review.approved:
selected_value = review.approved
else:
selected_value = trans.model.ComponentReview.approved_states.NO
revision_approved_select_field = grids_util.build_approved_select_field(
trans, name="revision_approved", selected_value=selected_value, for_component=False
)
rev, changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(repo, review.changeset_revision)
return trans.fill_template(
"/webapps/tool_shed/repository_review/edit_review.mako",
repository=repository,
review=review,
changeset_revision_label=changeset_revision_label,
revision_approved_select_field=revision_approved_select_field,
components_dict=components_dict,
message=message,
status=status,
)
@web.expose
@require_login("manage components")
def manage_components(self, trans, **kwd):
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "create":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="create_component", **kwd)
)
elif operation == "edit":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="edit_component", **kwd)
)
if "message" not in kwd:
message = "This is a list of repository components (features) that can be reviewed. You can add new components or change "
message += "the description of an existing component if appropriate. Click on the name link to change the description."
status = "warning"
kwd["message"] = message
kwd["status"] = status
return self.component_grid(trans, **kwd)
@web.expose
@require_login("manage repositories ready for review")
def manage_repositories_ready_for_review(self, trans, **kwd):
"""
A repository is ready to be reviewed if one of the following conditions is met:
1) It contains no tools
2) It contains tools the tools_functionally_correct flag is set to True. This implies that the repository metadata revision was installed and tested
by the Tool Shed's install and test framework.
"""
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="create_review", **kwd)
)
if operation == "view_or_manage_repository":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
message = "Any of these repositories that contain tools have been installed into Galaxy and proven to be functionally correct by executing the tests defined "
message += "for each tool. Repositories that do not contain tools have not been installed into Galaxy. "
kwd["message"] = message
kwd["status"] = "warning"
return self.repositories_ready_for_review_grid(trans, **kwd)
@web.expose
@require_login("manage repositories reviewed by me")
def manage_repositories_reviewed_by_me(self, trans, **kwd):
# The value of the received id is the encoded repository id.
if "operation" in kwd:
kwd["mine"] = True
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repositories_with_reviews", **kwd)
)
self.repositories_reviewed_by_me_grid.title = "Repositories reviewed by me"
return self.repositories_reviewed_by_me_grid(trans, **kwd)
@web.expose
@require_login("manage repositories with invalid tests")
def manage_repositories_with_invalid_tests(self, trans, **kwd):
"""
Display a list of repositories that contain tools, have not yet been reviewed, and have invalid functional tests. Tests are defined as
invalid if they are missing from the tool config or if defined test data is not included in the repository.
"""
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="create_review", **kwd)
)
if operation == "view_or_manage_repository":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
message = "These repositories contain tools with missing functional tests or test data. "
kwd["message"] = message
kwd["status"] = "warning"
return self.repositories_with_no_tool_tests_grid(trans, **kwd)
@web.expose
@require_login("manage repositories with reviews")
def manage_repositories_with_reviews(self, trans, **kwd):
# The value of the received id is the encoded repository id.
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repository_reviews", **kwd)
)
if operation == "view_or_manage_repository":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
return self.repositories_with_reviews_grid(trans, **kwd)
@web.expose
@require_login("manage repositories without reviews")
def manage_repositories_without_reviews(self, trans, **kwd):
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="create_review", **kwd)
)
if operation == "view_or_manage_repository":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
return self.repositories_without_reviews_grid(trans, **kwd)
@web.expose
@require_login("manage repository reviews")
def manage_repository_reviews(self, trans, mine=False, **kwd):
# The value of the received id is the encoded repository id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
repository_id = kwd.get("id", None)
if repository_id:
repository = suc.get_repository_in_tool_shed(trans.app, repository_id)
repo = repository.hg_repo
metadata_revision_hashes = [
metadata_revision.changeset_revision for metadata_revision in repository.metadata_revisions
]
reviewed_revision_hashes = [review.changeset_revision for review in repository.reviews]
reviews_dict = {}
for changeset in hg_util.get_reversed_changelog_changesets(repo):
changeset_revision = str(repo[changeset])
if changeset_revision in metadata_revision_hashes or changeset_revision in reviewed_revision_hashes:
rev, changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(
repo, changeset_revision
)
if changeset_revision in reviewed_revision_hashes:
# Find the review for this changeset_revision
repository_reviews = review_util.get_reviews_by_repository_id_changeset_revision(
trans.app, repository_id, changeset_revision
)
# Determine if the current user can add a review to this revision.
can_add_review = trans.user not in [
repository_review.user for repository_review in repository_reviews
]
repository_metadata = metadata_util.get_repository_metadata_by_changeset_revision(
trans.app, repository_id, changeset_revision
)
if repository_metadata:
repository_metadata_reviews = util.listify(repository_metadata.reviews)
else:
repository_metadata_reviews = []
else:
repository_reviews = []
repository_metadata_reviews = []
can_add_review = True
installable = changeset_revision in metadata_revision_hashes
revision_dict = dict(
changeset_revision_label=changeset_revision_label,
repository_reviews=repository_reviews,
repository_metadata_reviews=repository_metadata_reviews,
installable=installable,
can_add_review=can_add_review,
)
reviews_dict[changeset_revision] = revision_dict
return trans.fill_template(
"/webapps/tool_shed/repository_review/reviews_of_repository.mako",
repository=repository,
reviews_dict=reviews_dict,
mine=mine,
message=message,
status=status,
)
@web.expose
@require_login("manage repository reviews of revision")
def manage_repository_reviews_of_revision(self, trans, **kwd):
# The value of the received id is the encoded repository id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
repository_id = kwd.get("id", None)
changeset_revision = kwd.get("changeset_revision", None)
repository = repository_util.get_repository_in_tool_shed(trans.app, repository_id)
repo = repository.hg_repo
installable = changeset_revision in [
metadata_revision.changeset_revision for metadata_revision in repository.metadata_revisions
]
rev, changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(repo, changeset_revision)
reviews = review_util.get_reviews_by_repository_id_changeset_revision(
trans.app, repository_id, changeset_revision
)
return trans.fill_template(
"/webapps/tool_shed/repository_review/reviews_of_changeset_revision.mako",
repository=repository,
changeset_revision=changeset_revision,
changeset_revision_label=changeset_revision_label,
reviews=reviews,
installable=installable,
message=message,
status=status,
)
@web.expose
@require_login("repository reviews by user")
def repository_reviews_by_user(self, trans, **kwd):
if "operation" in kwd:
operation = kwd["operation"].lower()
# The value of the received id is the encoded review id.
review = review_util.get_review(trans.app, kwd["id"])
repository = review.repository
kwd["id"] = trans.security.encode_id(repository.id)
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repository_reviews", **kwd)
)
if operation == "view_or_manage_repository":
kwd["changeset_revision"] = review.changeset_revision
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
# The user may not be the current user. The value of the received id is the encoded user id.
user = suc.get_user(trans.app, kwd["id"])
self.repository_reviews_by_user_grid.title = f"All repository revision reviews for user '{user.username}'"
return self.repository_reviews_by_user_grid(trans, **kwd)
@web.expose
@require_login("reviewed repositories i own")
def reviewed_repositories_i_own(self, trans, **kwd):
# The value of the received id is the encoded repository id.
if "operation" in kwd:
operation = kwd["operation"].lower()
if operation == "inspect repository revisions":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="manage_repository_reviews", **kwd)
)
if operation == "view_or_manage_repository":
return trans.response.send_redirect(
web.url_for(controller="repository_review", action="view_or_manage_repository", **kwd)
)
return self.reviewed_repositories_i_own_grid(trans, **kwd)
@web.expose
@require_login("select previous review")
def select_previous_review(self, trans, **kwd):
# The value of the received id is the encoded repository id.
message = escape(kwd.get("message", ""))
status = kwd.get("status", "done")
repository = repository_util.get_repository_in_tool_shed(trans.app, kwd["id"])
changeset_revision = kwd.get("changeset_revision", None)
repo = repository.hg_repo
previous_reviews_dict = review_util.get_previous_repository_reviews(trans.app, repository, changeset_revision)
rev, changeset_revision_label = hg_util.get_rev_label_from_changeset_revision(repo, changeset_revision)
return trans.fill_template(
"/webapps/tool_shed/repository_review/select_previous_review.mako",
repository=repository,
changeset_revision=changeset_revision,
changeset_revision_label=changeset_revision_label,
previous_reviews_dict=previous_reviews_dict,
message=message,
status=status,
)
@web.expose
@require_login("view or manage repository")
def view_or_manage_repository(self, trans, **kwd):
repository = repository_util.get_repository_in_tool_shed(trans.app, kwd["id"])
if trans.user_is_admin or repository.user == trans.user:
return trans.response.send_redirect(web.url_for(controller="repository", action="manage_repository", **kwd))
else:
return trans.response.send_redirect(web.url_for(controller="repository", action="view_repository", **kwd))
+1 -123
View File
@@ -20,7 +20,6 @@ from sqlalchemy import (
Column,
DateTime,
desc,
false,
ForeignKey,
Integer,
not_,
@@ -132,7 +131,6 @@ class User(Base, Dictifiable, _HasTable):
& not_(Role.name == User.email) # type: ignore[has-type]
),
)
repository_reviews = relationship("RepositoryReview", back_populates="user")
def __init__(self, email=None, password=None):
self.email = email
@@ -375,8 +373,6 @@ class Repository(Base, Dictifiable, _HasTable):
back_populates="repository",
)
roles = relationship("RepositoryRoleAssociation", back_populates="repository")
reviews = relationship("RepositoryReview", back_populates="repository")
reviewers = relationship("User", secondary=lambda: RepositoryReview.__table__, viewonly=True) # type: ignore
dict_collection_visible_keys = [
"id",
@@ -541,114 +537,6 @@ class Repository(Base, Dictifiable, _HasTable):
return rval
class RepositoryReview(Base, Dictifiable, _HasTable):
__tablename__ = "repository_review"
id = Column(Integer, primary_key=True)
create_time = Column(DateTime, default=now)
update_time = Column(DateTime, default=now, onupdate=now)
repository_id = Column(ForeignKey("repository.id"), index=True)
changeset_revision = Column(TrimmedString(255), index=True)
user_id = Column(ForeignKey("galaxy_user.id"), index=True, nullable=False)
approved = Column(TrimmedString(255))
rating = Column(Integer, index=True)
deleted = Column(Boolean, index=True, default=False)
repository = relationship("Repository", back_populates="reviews")
# Take care when using the mapper below! It should be used only when a new review is being created for a repository change set revision.
# Keep in mind that repository_metadata records can be removed from the database for certain change set revisions when metadata is being
# reset on a repository!
repository_metadata = relationship(
"RepositoryMetadata",
viewonly=True,
foreign_keys=lambda: [RepositoryReview.repository_id, RepositoryReview.changeset_revision],
primaryjoin=lambda: (
(RepositoryReview.repository_id == RepositoryMetadata.repository_id) # type: ignore[has-type]
& (RepositoryReview.changeset_revision == RepositoryMetadata.changeset_revision) # type: ignore[has-type]
),
back_populates="reviews",
)
user = relationship("User", back_populates="repository_reviews")
component_reviews = relationship(
"ComponentReview",
viewonly=True,
primaryjoin=lambda: (
(RepositoryReview.id == ComponentReview.repository_review_id) # type: ignore[has-type]
& (ComponentReview.deleted == false()) # type: ignore[has-type]
),
back_populates="repository_review",
)
private_component_reviews = relationship(
"ComponentReview",
viewonly=True,
primaryjoin=lambda: (
(RepositoryReview.id == ComponentReview.repository_review_id) # type: ignore[has-type]
& (ComponentReview.deleted == false()) # type: ignore[has-type]
& (ComponentReview.private == true()) # type: ignore[has-type]
),
)
dict_collection_visible_keys = ["id", "repository_id", "changeset_revision", "user_id", "rating", "deleted"]
dict_element_visible_keys = ["id", "repository_id", "changeset_revision", "user_id", "rating", "deleted"]
approved_states = Bunch(NO="no", YES="yes")
def __init__(self, deleted=False, **kwd):
super().__init__(**kwd)
self.deleted = deleted
class ComponentReview(Base, Dictifiable, _HasTable):
__tablename__ = "component_review"
id = Column(Integer, primary_key=True)
create_time = Column(DateTime, default=now)
update_time = Column(DateTime, default=now, onupdate=now)
repository_review_id = Column(ForeignKey("repository_review.id"), index=True)
component_id = Column(ForeignKey("component.id"), index=True)
comment = Column(TEXT)
private = Column(Boolean, default=False)
approved = Column(TrimmedString(255))
rating = Column(Integer)
deleted = Column(Boolean, index=True, default=False)
repository_review = relationship("RepositoryReview", back_populates="component_reviews")
component = relationship("Component")
dict_collection_visible_keys = [
"id",
"repository_review_id",
"component_id",
"private",
"approved",
"rating",
"deleted",
]
dict_element_visible_keys = [
"id",
"repository_review_id",
"component_id",
"private",
"approved",
"rating",
"deleted",
]
approved_states = Bunch(NO="no", YES="yes", NA="not_applicable")
def __init__(self, private=False, approved=False, deleted=False, **kwd):
super().__init__(**kwd)
self.private = private
self.approved = approved
self.deleted = deleted
class Component(Base, _HasTable):
__tablename__ = "component"
id = Column(Integer, primary_key=True)
name = Column(TrimmedString(255))
description = Column(TEXT)
class ItemRatingAssociation(_HasTable):
def __init__(self, id=None, user=None, item=None, rating=0, comment=""):
self.id = id
@@ -841,23 +729,13 @@ class RepositoryMetadata(Dictifiable, _HasTable):
# After the map_imperatively statement has been executed, the members of the
# properties dictionary (repository, reviews) will be available as instrumented
# properties dictionary (repository) will be available as instrumented
# class attributes on RepositoryMetadata.
mapper_registry.map_imperatively(
RepositoryMetadata,
RepositoryMetadata.table,
properties=dict(
repository=relationship(Repository, back_populates="metadata_revisions"),
reviews=relationship(
RepositoryReview,
viewonly=True,
foreign_keys=lambda: [RepositoryReview.repository_id, RepositoryReview.changeset_revision],
primaryjoin=lambda: (
(RepositoryReview.repository_id == RepositoryMetadata.repository_id)
& (RepositoryReview.changeset_revision == RepositoryMetadata.changeset_revision)
),
back_populates="repository_metadata",
),
),
)
-32
View File
@@ -164,18 +164,6 @@ class CommunityRBACAgent(RBACAgent):
return None
return role
def get_repository_reviewer_role(self):
return (
self.sa_session.query(self.model.Role)
.filter(
and_(
self.model.Role.table.c.name == "Repository Reviewer",
self.model.Role.table.c.type == self.model.Role.types.SYSTEM,
)
)
.first()
)
def set_entity_group_associations(self, groups=None, users=None, roles=None, delete_existing_assocs=True):
if groups is None:
groups = []
@@ -283,26 +271,6 @@ class CommunityRBACAgent(RBACAgent):
return True
return False
def user_can_review_repositories(self, user):
if user:
roles = user.all_roles()
if roles:
repository_reviewer_role = self.get_repository_reviewer_role()
if repository_reviewer_role:
return repository_reviewer_role in roles
return False
def user_can_browse_component_review(self, app, repository, component_review, user):
if component_review and user:
if self.can_push(app, user, repository):
# A user with write permission on the repository can access private/public component reviews.
return True
else:
if self.user_can_review_repositories(user):
# Reviewers can access private/public component reviews.
return True
return False
def get_permitted_actions(filter=None):
"""Utility method to return a subset of RBACAgent's permitted actions"""
@@ -31,7 +31,6 @@
</%def>
<%def name="left_panel()">
<% can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user ) %>
<div class="unified-panel-header" unselectable="on">
<div class='unified-panel-header-inner'>Administration</div>
</div>
@@ -152,19 +152,3 @@
${heads_str}
</div>
</%def>
<%def name="render_review_comment( comment_text )">
<style type="text/css">
#reviews_table{ table-layout:fixed;
width:100%;
overflow-wrap:normal;
overflow:hidden;
border:0px;
word-break:keep-all;
word-wrap:break-word;
line-break:strict; }
</style>
<table id="reviews_table">
<tr><td>${comment_text}</td></tr>
</table>
</%def>
@@ -2,7 +2,6 @@
<%def name="render_tool_shed_repository_actions( repository, metadata=None, changeset_revision=None )">
<%
from tool_shed.util.review_util import can_browse_repository_reviews, changeset_revision_reviewed_by_user, get_review_by_repository_id_changeset_revision_user_id
from tool_shed.util.metadata_util import is_malicious
if repository.metadata_revisions:
@@ -34,11 +33,6 @@
can_browse_contents = not is_new
if can_browse_repository_reviews( trans.app, trans.user, repository ):
can_browse_reviews = True
else:
can_browse_reviews = False
if trans.user and trans.user != repository.user:
can_contact_owner = True
else:
@@ -73,28 +67,6 @@
can_rate = True
else:
can_rate = False
if metadata is not None and changeset_revision is not None:
if has_metadata and not is_deprecated and trans.app.security_agent.user_can_review_repositories( trans.user ):
can_review_repository = True
else:
can_review_repository = False
if changeset_revision_reviewed_by_user( trans.user, repository, changeset_revision ):
reviewed_by_user = True
else:
reviewed_by_user = False
else:
can_review_repository = False
reviewed_by_user = False
if reviewed_by_user:
review = get_review_by_repository_id_changeset_revision_user_id( app=trans.app,
repository_id=trans.security.encode_id( repository.id ),
changeset_revision=changeset_revision,
user_id=trans.security.encode_id( trans.user.id ) )
review_id = trans.security.encode_id( review.id )
else:
review_id = None
if not is_new and not is_deprecated:
can_set_metadata = True
@@ -134,16 +106,6 @@
%else:
<li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
%endif
%if can_browse_reviews:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repository_reviews', id=trans.app.security.encode_id( repository.id ) )}">Browse reviews of this repository</a>
%endif
%if can_upload:
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
%endif
@@ -28,7 +28,6 @@
</%def>
<%def name="left_panel()">
<% can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user ) %>
<div class="unified-panel-header" unselectable="on">
<div class='unified-panel-header-inner'>${trans.app.shed_counter.unique_valid_tools | h} valid tools on ${util.unicodify( trans.app.shed_counter.generation_time ) | h}</div>
</div>
@@ -93,11 +92,6 @@
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_i_can_administer' )}">Repositories I can administer</a>
</div>
%endif
%if has_reviewed_repositories:
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='reviewed_repositories_i_own' )}">Reviewed repositories I own</a>
</div>
%endif
%if has_deprecated_repositories:
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_deprecated_repositories_i_own' )}">Deprecated repositories I own</a>
@@ -128,59 +122,6 @@
<a target="galaxy_main" href="${h.url_for( controller='repository', action='create_galaxy_docker_image' )}">Create Galaxy Docker Image</a>
</div>
%endif
%if can_review_repositories:
<div class="toolSectionPad"></div>
<div class="toolSectionTitle">
Reviewing Repositories
</div>
<div class="toolSectionBody">
<div class="toolSectionBg">
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_ready_for_review' )}">Repositories ready for review</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_without_reviews' )}">All repositories with no reviews</a>
</div>
%if trans.user.repository_reviews:
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_reviewed_by_me' )}">Repositories reviewed by me</a>
</div>
%endif
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_with_reviews' )}">All reviewed repositories</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_components' )}">Manage review components</a>
</div>
</div>
</div>
<div class="toolSectionPad"></div>
<div class="toolSectionTitle">
Reviewing Repositories With Tools
</div>
<div class="toolSectionBody">
<div class="toolSectionBg">
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_missing_tool_test_components' )}">Latest revision: missing tool tests</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_install_errors' )}">Latest revision: installation errors</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_failing_tool_tests' )}">Latest revision: failing tool tests</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_skip_tool_test_checked' )}">Latest revision: skip tool tests</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_no_failing_tool_tests' )}">Latest revision: all tool tests pass</a>
</div>
<div class="toolTitle">
<a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories_with_invalid_tools' )}">Latest revision: invalid tools</a>
</div>
</div>
</div>
%endif
%else:
<div class="toolSectionPad"></div>
<div class="toolSectionTitle">
@@ -38,11 +38,6 @@
else:
can_download = False
if has_metadata and not is_deprecated and trans.app.security_agent.user_can_review_repositories( trans.user ):
can_review_repository = True
else:
can_review_repository = False
if not is_new and not is_deprecated:
can_set_metadata = True
else:
@@ -132,11 +127,7 @@ ${render_tool_shed_repository_actions( repository, metadata=metadata, changeset_
<div class="form-row">
${render_select(changeset_revision_select_field)} <i>${tip_str}</i>
<div class="toolParamHelp" style="clear: both;">
%if can_review_repository:
Select a revision to inspect for adding or managing a review or for download or installation.
%else:
Select a revision to inspect for download or installation.
%endif
Select a revision to inspect for download or installation.
</div>
</div>
</form>
@@ -343,47 +334,6 @@ ${render_repository_items( metadata, containers_dict, can_set_metadata=True, ren
</div>
</div>
<p/>
<div class="toolForm">
<div class="toolFormBody">
%if display_reviews:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='view_repository', id=trans.security.encode_id( repository.id ), display_reviews=False )}"><label>Hide Reviews</label></a>
</div>
<div style="clear: both"></div>
<div class="form-row">
<table class="grid">
<thead>
<tr>
<th>Rating</th>
<th>Comments</th>
<th>Reviewed</th>
<th>User</th>
</tr>
</thead>
<% count = 0 %>
%for review in repository.ratings:
<%
count += 1
name = 'rating%d' % count
%>
<tr>
<td>${render_star_rating( name, review.rating, disabled=True )}</td>
<td>${render_review_comment( to_html_string( review.comment ) )}</td>
<td>${time_ago( review.update_time )}</td>
<td>${review.user.username | h}</td>
</tr>
%endfor
</table>
</div>
<div style="clear: both"></div>
%else:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='view_repository', id=trans.security.encode_id( repository.id ), display_reviews=True )}"><label>Display Reviews</label></a>
</div>
<div style="clear: both"></div>
%endif
</div>
</div>
%endif
<p/>
%if can_set_malicious:
@@ -92,19 +92,6 @@ ${render_tool_shed_repository_actions( repository, metadata=None, changeset_revi
${render_star_rating( 'rating', rating )}
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Review:</label>
%if rra and rra.comment:
<div class="form-row-input">
<pre><textarea name="comment" rows="5" cols="80">${rra.comment | h}</textarea></pre>
</div>
%else:
<div class="form-row-input">
<textarea name="comment" rows="5" cols="80"></textarea>
</div>
%endif
<div style="clear: both"></div>
</div>
<div class="form-row">
<input type="submit" name="rate_button" id="rate_button" value="Submit" />
</div>
@@ -112,42 +99,4 @@ ${render_tool_shed_repository_actions( repository, metadata=None, changeset_revi
</div>
</div>
<p/>
%if repository.ratings and ( len( repository.ratings ) > 1 or repository.ratings[0] != rra ):
<div class="toolForm">
<div class="toolFormBody">
%if display_reviews:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='rate_repository', id=trans.security.encode_id( repository.id ), display_reviews=False )}"><label>Hide Reviews</label></a>
</div>
<table class="grid">
<thead>
<tr>
<th>Rating</th>
<th>Comments</th>
<th>Reviewed</th>
<th>User</th>
</tr>
</thead>
<% count = 0 %>
%for review in repository.ratings:
<%
count += 1
name = 'rating%d' % count
%>
<tr>
<td>${render_star_rating( name, review.rating, disabled=True )}</td>
<td><pre>${review.comment | h}</pre></td>
<td>${time_ago( review.update_time )}</td>
<td>${review.user.username | h}</td>
</tr>
%endfor
</table>
%else:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='rate_repository', id=trans.security.encode_id( repository.id ), display_reviews=True )}"><label>Display Reviews</label></a>
</div>
%endif
</div>
</div>
%endif
%endif
@@ -230,47 +230,5 @@ ${render_repository_items( metadata, containers_dict, can_set_metadata=False, re
</div>
</div>
</div>
<p/>
<div class="toolForm">
<div class="toolFormBody">
%if display_reviews:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='view_repository', id=trans.security.encode_id( repository.id ), display_reviews=False )}"><label>Hide Reviews</label></a>
</div>
<div style="clear: both"></div>
<div class="form-row">
<table class="grid">
<thead>
<tr>
<th>Rating</th>
<th>Comments</th>
<th>Reviewed</th>
<th>User</th>
</tr>
</thead>
<% count = 0 %>
%for review in repository.ratings:
<%
count += 1
name = 'rating%d' % count
%>
<tr>
<td>${render_star_rating( name, review.rating, disabled=True )}</td>
<td>${render_review_comment( to_html_string( review.comment ) )}</td>
<td>${time_ago( review.update_time )}</td>
<td>${review.user.username}</td>
</tr>
%endfor
</table>
</div>
<div style="clear: both"></div>
%else:
<div class="form-row">
<a href="${h.url_for( controller='repository', action='view_repository', id=trans.security.encode_id( repository.id ), display_reviews=True )}"><label>Display Reviews</label></a>
</div>
<div style="clear: both"></div>
%endif
</div>
</div>
%endif
<p/>
@@ -1,118 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%namespace file="/webapps/tool_shed/common/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
<%
from galaxy.web.form_builder import CheckboxField
from tool_shed.util.container_util import STRSEP
from tool_shed.util.basic_util import to_html_string
%>
<%def name="stylesheets()">
${h.css('base')}
</%def>
<%def name="javascripts()">
${parent.javascripts()}
</%def>
${render_tool_shed_repository_actions( repository=repository, changeset_revision=review.changeset_revision )}
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">Review of repository '${repository.name | h}'</div>
<div class="toolFormBody">
<div class="form-row">
<label>Reviewer:</label>
${review.user.username}
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Repository revision:</label>
<a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">${changeset_revision_label}</a>
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Repository owner:</label>
${repository.user.username | h}
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Repository synopsis:</label>
${repository.description | h}
<div style="clear: both"></div>
</div>
<div class="form-row">
%if review.component_reviews:
<table class="grid">
%for component_review in review.component_reviews:
<%
can_browse = trans.app.security_agent.user_can_browse_component_review( trans.app, repository, component_review, trans.user )
component = component_review.component
if can_browse:
# Initialize Private check box.
private_check_box_name = '%s%sprivate' % ( component.name, STRSEP )
private_check_box = CheckboxField( name=private_check_box_name, value=component_review.private )
# Initialize star rating.
rating_name = '%s%srating' % ( component.name, STRSEP )
%>
<tr>
<td bgcolor="#D8D8D8"><b>${component.name | h}</b></td>
<td bgcolor="#D8D8D8">${component.description | h}</td>
</tr>
<tr>
<td colspan="2">
%if can_browse:
<table class="grid">
<tr>
<td>
<label>Private:</label>
${render_checkbox(private_check_box, disabled=True)}
<div class="toolParamHelp" style="clear: both;">
A private review can be accessed only by the owner of the repository and authorized repository reviewers.
</div>
<div style="clear: both"></div>
</td>
</tr>
%if component_review.comment:
<tr>
<td>
<div overflow-wrap:normal;overflow:hidden;word-break:keep-all;word-wrap:break-word;line-break:strict;>
${ to_html_string( component_review.comment ) }
</div>
</td>
</tr>
%endif
<tr>
<td>
<label>Approved:</label>
${component_review.approved | h}
<div style="clear: both"></div>
</td>
</tr>
<tr>
<td>
<label>Rating:</label>
${render_star_rating( rating_name, component_review.rating, disabled=True )}
<div style="clear: both"></div>
</td>
</tr>
</table>
%else:
You are not authorized to access the review of this component since it has been marked private.
%endif
</td>
</tr>
%endfor
</table>
%else:
This review has not yet been started.
%endif
</div>
</div>
</div>
@@ -1,34 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%def name="javascripts()">
${parent.javascripts()}
<script type="text/javascript">
$(function(){
$("input:text:first").focus();
})
</script>
</%def>
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">Create Component</div>
<div class="toolFormBody">
<form name="create_component" id="create_component" action="${h.url_for( controller='repository_review', action='create_component' )}" method="post" >
<div class="form-row">
<label>Name:</label>
<input name="name" type="textfield" value="${name | h}" size=40"/>
</div>
<div class="form-row">
<label>Description:</label>
<input name="description" type="textfield" value="${description | h}" size=40"/>
</div>
<div class="form-row">
<input type="submit" name="create_component_button" value="Save"/>
</div>
</form>
</div>
</div>
@@ -1,37 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">Change component description</div>
<div class="toolFormBody">
<form name="edit_component" action="${h.url_for( controller='repository_review', action='edit_component' )}" method="post" >
<div class="form-row">
<label>Name:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${component.name | h}
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Description:</label>
<div style="float: left; width: 250px; margin-right: 10px;">
<input name="description" type="textfield" value="${component.description | h}" size=40"/>
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<div style="float: left; width: 250px; margin-right: 10px;">
<input type="hidden" name="id" value="${trans.security.encode_id( component.id )}"/>
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<input type="submit" name="edit_component_button" value="Save"/>
</div>
</form>
</div>
</div>
@@ -1,162 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%namespace file="/webapps/tool_shed/common/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
<%
from galaxy.web.form_builder import CheckboxField
from tool_shed.grids.util import build_approved_select_field
from tool_shed.util.container_util import STRSEP
%>
<%def name="stylesheets()">
${h.css('base')}
</%def>
<%def name="javascripts()">
${parent.javascripts()}
</%def>
${render_tool_shed_repository_actions( repository=repository, changeset_revision=review.changeset_revision )}
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">My review of repository '${repository.name | h}'</div>
<div class="toolFormBody">
<form name="edit_review" action="${h.url_for( controller='repository_review', action='edit_review', id=trans.security.encode_id( review.id ) )}" method="post" >
<div class="form-row">
<label>Repository revision:</label>
<a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">${changeset_revision_label}</a>
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Repository owner:</label>
${repository.user.username | h}
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Repository synopsis:</label>
${repository.description | h}
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Approve this repository revision?</label>
${render_select(revision_approved_select_field)}
<div class="toolParamHelp" style="clear: both;">
Individual components below may be approved without approving the repository revision.
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<input type="submit" name="revision_approved_button" value="Save"/>
<div class="toolParamHelp" style="clear: both;">
All changes made on this page will be saved when any <b>Save</b> button is clicked.
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<table class="grid">
%for component_name, component_review_dict in components_dict.items():
<%
component = component_review_dict[ 'component' ]
encoded_component_id = trans.security.encode_id( component.id )
component_review = component_review_dict[ 'component_review' ]
if component_review:
comment = component_review.comment or ''
rating = component_review.rating
approved_select_field_selected_value = component_review.approved
private = component_review.private
else:
comment = ''
rating = 0
approved_select_field_selected_value = None
private = False
# Initialize Approved select field.
approved_select_field_name = '%s%sapproved' % ( component_name, STRSEP )
approved_select_field = build_approved_select_field( trans, name=approved_select_field_name, selected_value=approved_select_field_selected_value, for_component=True )
# Initialize Private check box.
private_check_box_name = '%s%sprivate' % ( component_name, STRSEP )
private_check_box = CheckboxField( name=private_check_box_name, value=private )
# Initialize star rating.
rating_name = '%s%srating' % ( component_name, STRSEP )
# Initialize comment text area.
comment_name = '%s%scomment' % ( component_name, STRSEP )
# Initialize the component id form field name.
component_id_name = '%s%scomponent_id' % ( component_name, STRSEP )
# Initialize the Save button.
review_button_name = '%s%sreview_button' % ( component_name, STRSEP )
%>
<tr>
<td bgcolor="#D8D8D8"><b>${component.name | h}</b></td>
<td bgcolor="#D8D8D8">${component.description | h}</td>
</tr>
<tr>
<td colspan="2">
<table class="grid">
<tr>
<td>
<label>Mark private:</label>
${render_checkbox(private_check_box)}
<div class="toolParamHelp" style="clear: both;">
A private review can be accessed only by the owner of the repository and authorized repository reviewers.
</div>
<div style="clear: both"></div>
</td>
</tr>
<tr>
<td>
<label>Comments:</label>
%if component_review:
<pre><textarea name="${comment_name}" rows="3" cols="80">${comment | h}</textarea></pre>
%else:
<textarea name="${comment_name}" rows="3" cols="80"></textarea>
%endif
<div style="clear: both"></div>
</td>
</tr>
<tr>
<td>
<label>Approved:</label>
${render_select(approved_select_field)}
<div style="clear: both"></div>
</td>
</tr>
<tr>
<td>
<label>Rating:</label>
${render_star_rating( rating_name, rating )}
<div style="clear: both"></div>
<div class="toolParamHelp" style="clear: both;">
Rate this component only - the average of all component ratings defines the value of the repository rating.
</div>
</td>
</tr>
<tr>
<td>
<input type="hidden" name="${component_id_name}" value="${encoded_component_id}"/>
<input type="submit" name="${review_button_name}" value="Save"/>
<div style="clear: both"></div>
<div class="toolParamHelp" style="clear: both;">
All changes made on this page will be saved when any <b>Save</b> button is clicked.
</div>
</td>
</tr>
</table>
</td>
</tr>
%endfor
</table>
</div>
</form>
</div>
</div>
@@ -1 +0,0 @@
<%inherit file="/legacy/grid_base.mako"/>
@@ -1,112 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%namespace file="/webapps/tool_shed/common/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/repository/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
<%
from tool_shed.grids.util import build_approved_select_field
from tool_shed.util.container_util import STRSEP
if installable:
installable_str = 'yes'
else:
installable_str = 'no'
can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user )
%>
<%!
def inherit(context):
if context.get('use_panels'):
return '/webapps/tool_shed/base_panels.mako'
else:
return '/base.mako'
%>
<%inherit file="${inherit(context)}"/>
<%def name="stylesheets()">
${h.css('base')}
</%def>
<%def name="javascripts()">
${parent.javascripts()}
${common_javascripts(repository)}
</%def>
${render_tool_shed_repository_actions( repository=repository, changeset_revision=changeset_revision )}
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">Revision reviews of repository '${repository.name | h}'</div>
<div class="toolFormBody">
<div class="form-row">
<label>Revision:</label>
<a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
<div style="clear: both"></div>
</div>
<div class="form-row">
<label>Revision is installable:</label>
${installable_str | h}
<div style="clear: both"></div>
</div>
<div class="form-row">
%if reviews:
<table class="grid">
<tr>
<th>Reviewer</th>
<th>Repository rating</th>
<th>Approved</th>
<th></th>
</tr>
%for review in reviews:
<%
encoded_review_id = trans.security.encode_id( review.id )
approved_select_field_name = '%s%sapproved' % ( encoded_review_id, STRSEP )
approved_select_field_selected_value = review.approved
approved_select_field = build_approved_select_field( trans, name=approved_select_field_name, selected_value=approved_select_field_selected_value, for_component=False )
if review.approved not in [ None, 'None', 'none' ]:
approved_str = review.approved
else:
approved_str = ''
repository_rating_name = '%srepository_rating' % encoded_review_id
%>
<tr>
<td>
<div style="float:left;" class="menubutton split popup" id="${encoded_review_id}-popup">
<a class="view-info" href="${h.url_for( controller='repository_review', action='repository_reviews_by_user', id=trans.security.encode_id( review.user.id ) )}">${review.user.username | h}</a>
</div>
<div popupmenu="${encoded_review_id}-popup">
%if review.user == trans.user:
<a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=encoded_review_id )}">Edit my review</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='browse_review', id=encoded_review_id )}">Browse this review</a>
%endif
</div>
</td>
<td>${render_star_rating( repository_rating_name, review.rating, disabled=True )}</td>
%if review.user == trans.user:
<form name="approve_repository_review" action="${h.url_for( controller='repository_review', action='approve_repository_review', id=encoded_review_id ) }" method="post" >
<td>${render_select(approved_select_field)}</td>
<td><input type="submit" name="approve_repository_review_button" value="Save"/></td>
</form>
%else:
<td>${approved_str | h}</td>
<td></td>
%endif
</tr>
%endfor
</table>
%else:
<label>This repository revision has not yet been reviewed:</label>
%if can_review_repositories:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
<div style="clear: both"></div>
%endif
%endif
</div>
<div style="clear: both"></div>
</div>
</div>
@@ -1,87 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%namespace file="/webapps/tool_shed/common/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/repository/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
<%
if mine:
title = "My reviews of repository '%s'" % repository.name
else:
title = "All reviews of repository '%s'" % repository.name
%>
<%!
def inherit(context):
if context.get('use_panels'):
return '/webapps/tool_shed/base_panels.mako'
else:
return '/base.mako'
%>
<%inherit file="${inherit(context)}"/>
<%def name="javascripts()">
${parent.javascripts()}
${common_javascripts(repository)}
</%def>
${render_tool_shed_repository_actions( repository=repository )}
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
<div class="toolFormTitle">${title | h}</div>
<div class="toolFormBody">
<div class="form-row">
<table class="grid">
<tr>
<th>Revision</th>
<th>Reviewers</th>
<th>Installable</th>
</tr>
%for changeset_revision, revision_dict in reviews_dict.items():
<%
changeset_revision_label = revision_dict[ 'changeset_revision_label' ]
repository_reviews = revision_dict[ 'repository_reviews' ]
repository_metadata_reviews = revision_dict[ 'repository_metadata_reviews' ]
reviewers_str = ''
if repository_reviews:
for repository_review in repository_reviews:
reviewers_str += '<a class="view-info" href="'
if repository_review.user == trans.user:
reviewers_str += 'edit_review'
else:
reviewers_str += 'browse_review'
reviewers_str += '?id=%s">%s</a>' % ( trans.security.encode_id( repository_review.id ), repository_review.user.username )
reviewers_str += ' | '
reviewers_str = reviewers_str.rstrip( '| ' )
if revision_dict[ 'installable' ]:
installable_str = 'yes'
else:
installable_str = ''
can_add_review = revision_dict[ 'can_add_review' ]
%>
<tr>
<td>
<div style="float:left;" class="menubutton split popup" id="${changeset_revision}-popup">
<a class="view-info" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
</div>
<div popupmenu="${changeset_revision}-popup">
%if repository_reviews:
<a class="action-button" href="${h.url_for( controller='repository_review', action='manage_repository_reviews_of_revision', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Browse reviews of this revision</a>
%elif can_add_review:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
</div>
</td>
<td>${reviewers_str}</td>
<td>${installable_str | h}</td>
</tr>
%endfor
</table>
</div>
<div style="clear: both"></div>
</div>
</div>
@@ -1,89 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%namespace file="/webapps/tool_shed/common/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/repository/common.mako" import="*" />
<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
<%!
def inherit(context):
if context.get('use_panels'):
return '/webapps/tool_shed/base_panels.mako'
else:
return '/base.mako'
%>
<%inherit file="${inherit(context)}"/>
<%def name="stylesheets()">
${h.css('base')}
</%def>
<%def name="javascripts()">
${parent.javascripts()}
${common_javascripts(repository)}
</%def>
${render_tool_shed_repository_actions( repository=repository )}
%if message:
${render_msg( message, status )}
%endif
<div class="warningmessage">
You have elected to create a new review for revision <b>${changeset_revision_label}</b>of this repository. Since previous revisions have been reviewed,
you can select a previous review to copy to your new review, or click the <b>Create a review without copying</b> button.
</div>
<div class="toolForm">
<div class="toolFormTitle">Select previous revision review of repository '${repository.name | h}'</div>
<div class="toolFormBody">
<div class="form-row">
<label>Revision for new review:</label>
<a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
<div style="clear: both"></div>
</div>
<div class="form-row">
<table class="grid">
<tr>
</tr>
<td bgcolor="#D8D8D8" colspan="4"><b>Previous revision reviews of repository '${repository.name | h}' that can be copied to your new review</b></td>
<tr>
<th>Reviewer</th>
<th>Revision reviewed</th>
<th>Repository rating</th>
<th>Approved</th>
</tr>
%for previous_changeset_revision, previous_changeset_revision_dict in previous_reviews_dict.items():
<%
previous_changeset_revision_label = previous_changeset_revision_dict[ 'changeset_revision_label' ]
previous_reviews = previous_changeset_revision_dict[ 'reviews' ]
%>
%for review in previous_reviews:
<%
encoded_review_id = trans.security.encode_id( review.id )
if review.approved not in [ None, 'None', 'none' ]:
approved_str = review.approved
else:
approved_str = ''
repository_rating_name = '%srepository_rating' % encoded_review_id
%>
<tr>
<td>
<div style="float:left;" class="menubutton split popup" id="${encoded_review_id}-popup">
<a class="view-info" href="${h.url_for( controller='repository_review', action='browse_review', id=encoded_review_id )}">${review.user.username | h}</a>
</div>
<div popupmenu="${encoded_review_id}-popup">
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision, previous_review_id=encoded_review_id )}">Copy this review</a>
</div>
</td>
<td>${previous_changeset_revision_label}</td>
<td>${render_star_rating( repository_rating_name, review.rating, disabled=True )}</td>
<td>${approved_str | h}</td>
</tr>
%endfor
%endfor
</table>
</div>
<div style="clear: both"></div>
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, create_without_copying=True )}">Create a review without copying</a>
</div>
</div>
+1 -243
View File
@@ -94,69 +94,6 @@ class TestCategory(BaseTest):
assert stored_obj.repositories == [repository_category_association]
class TestComponent(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "component"
def test_columns(self, session, cls_):
name, description = "a", "b"
obj = cls_(name=name, description=description)
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.id == obj_id
assert stored_obj.name == name
assert stored_obj.description == description
class TestComponentReview(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "component_review"
def test_columns(self, session, cls_, repository_review, component):
create_time = datetime.now()
update_time = create_time + timedelta(hours=1)
comment = "a"
private = True
approved = "b"
rating = 1
deleted = True
obj = cls_()
obj.create_time = create_time
obj.update_time = update_time
obj.repository_review = repository_review
obj.component = component
obj.comment = comment
obj.private = private
obj.approved = approved
obj.rating = rating
obj.deleted = deleted
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.id == obj_id
assert stored_obj.create_time == create_time
assert stored_obj.update_time == update_time
assert stored_obj.repository_review_id == repository_review.id
assert stored_obj.component_id == component.id
assert stored_obj.comment == comment
assert stored_obj.private == private
assert stored_obj.approved == approved
assert stored_obj.rating == rating
assert stored_obj.deleted == deleted
def test_relationships(self, session, cls_, repository_review, component):
obj = cls_()
obj.repository_review = repository_review
obj.component = component
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.repository_review.id == repository_review.id
assert stored_obj.component.id == component.id
class TestGalaxySession(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "galaxy_session"
@@ -364,9 +301,7 @@ class TestRepository(BaseTest):
repository_rating_association,
repository_metadata_factory,
repository_role_association,
repository_review_factory,
user,
user_factory,
):
obj = cls_()
obj.user = user
@@ -374,16 +309,6 @@ class TestRepository(BaseTest):
obj.ratings.append(repository_rating_association)
obj.roles.append(repository_role_association)
reviewer1 = user_factory()
review1 = repository_review_factory()
review1.user = reviewer1
review1.repository = obj
reviewer2 = user_factory()
review2 = repository_review_factory()
review2.user = reviewer2
review2.repository = obj
metadata1 = repository_metadata_factory()
metadata1.repository = obj
metadata1.downloadable = False
@@ -400,12 +325,10 @@ class TestRepository(BaseTest):
assert stored_obj.categories == [repository_category_association]
assert stored_obj.ratings == [repository_rating_association]
assert stored_obj.roles == [repository_role_association]
assert collection_consists_of_objects(stored_obj.reviews, review1, review2)
assert collection_consists_of_objects(stored_obj.reviewers, reviewer1, reviewer2)
assert collection_consists_of_objects(stored_obj.metadata_revisions, metadata1, metadata2)
assert stored_obj.downloadable_revisions == [metadata2]
delete_from_database(session, [reviewer1, reviewer2, review1, review2, metadata1, metadata2])
delete_from_database(session, [metadata1, metadata2])
class TestRepositoryCategoryAssociation(BaseTest):
@@ -491,7 +414,6 @@ class TestRepositoryMetadata(BaseTest):
session,
cls_,
repository,
repository_review_factory,
user,
):
@@ -499,38 +421,6 @@ class TestRepositoryMetadata(BaseTest):
obj.repository = repository
obj.changeset_revision = "nonempty"
# create 3 reviews
review1 = repository_review_factory()
review2 = repository_review_factory()
review3 = repository_review_factory()
# set the same user for all reviews
review1.user = user
review2.user = user
review3.user = user
# set the same repository for all reviews
review1.repository = obj.repository
review2.repository = obj.repository
review3.repository = obj.repository
# set the same changeset for reviews 1,2
review1.changeset_revision = obj.changeset_revision
review2.changeset_revision = obj.changeset_revision
review3.changeset_revision = "something else" # this won't be in reviews for this metadata
# add to session
session.add(review1)
session.add(review2)
session.add(review3)
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.repository.id == repository.id
assert collection_consists_of_objects(stored_obj.reviews, review1, review2)
delete_from_database(session, [review1, review2, review3])
class TestRepositoryRatingAssociation(BaseTest):
def test_table(self, cls_):
@@ -571,106 +461,6 @@ class TestRepositoryRatingAssociation(BaseTest):
assert stored_obj.user.id == user.id
class TestRepositoryReview(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "repository_review"
def test_columns(self, session, cls_, repository, user):
create_time = datetime.now()
update_time = create_time + timedelta(hours=1)
changeset_revision = "a"
approved = "b"
rating = 1
deleted = True
obj = cls_()
obj.create_time = create_time
obj.update_time = update_time
obj.repository = repository
obj.changeset_revision = changeset_revision
obj.user = user
obj.approved = approved
obj.rating = rating
obj.deleted = deleted
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.id == obj_id
assert stored_obj.create_time == create_time
assert stored_obj.update_time == update_time
assert stored_obj.repository_id == repository.id
assert stored_obj.changeset_revision == changeset_revision
assert stored_obj.user_id == user.id
assert stored_obj.approved == approved
assert stored_obj.rating == rating
assert stored_obj.deleted == deleted
def test_relationships(
self, session, cls_, repository, user, repository_metadata_factory, component_review_factory
):
obj = cls_()
changeset = "nonempty"
obj.changeset_revision = changeset
obj.repository = repository
obj.user = user
metadata1 = repository_metadata_factory()
metadata2 = repository_metadata_factory()
metadata1.repository = repository
metadata2.repository = repository
metadata1.changeset_revision = changeset
metadata2.changeset_revision = "something else"
component_review1 = component_review_factory()
component_review1.repository_review = obj
component_review1.deleted = False
component_review2 = component_review_factory()
component_review2.repository_review = obj
component_review2.deleted = False
component_review2.private = True
session.add_all([metadata1, metadata2, component_review1, component_review2])
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.repository.id == repository.id
assert stored_obj.user.id == user.id
assert stored_obj.repository_metadata == metadata1
assert collection_consists_of_objects(stored_obj.component_reviews, component_review1, component_review2)
assert stored_obj.private_component_reviews == [component_review2]
delete_from_database(session, [component_review1, component_review2, metadata1, metadata2])
class TestRepositoryRoleAssociation(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "repository_role_association"
def test_columns(self, session, cls_, repository, role):
create_time = datetime.now()
update_time = create_time + timedelta(hours=1)
obj = cls_(repository, role)
obj.create_time = create_time
obj.update_time = update_time
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.id == obj_id
assert stored_obj.repository_id == repository.id
assert stored_obj.role_id == role.id
assert stored_obj.create_time == create_time
assert stored_obj.update_time == update_time
def test_relationships(self, session, cls_, repository, role):
obj = cls_(repository, role)
with dbcleanup(session, obj) as obj_id:
stored_obj = get_stored_obj(session, cls_, obj_id)
assert stored_obj.repository.id == repository.id
assert stored_obj.role.id == role.id
class TestRole(BaseTest):
def test_table(self, cls_):
assert cls_.__tablename__ == "role"
@@ -808,7 +598,6 @@ class TestUser(BaseTest):
repository,
galaxy_session,
api_keys,
repository_review,
role,
group,
password_reset_token,
@@ -825,7 +614,6 @@ class TestUser(BaseTest):
obj.api_keys.append(api_keys)
obj.reset_tokens.append(password_reset_token)
obj.groups.append(user_group_association)
obj.repository_reviews.append(repository_review)
_private_role = role_factory(name=obj.email)
private_user_role = user_role_association_factory(obj, _private_role)
@@ -842,7 +630,6 @@ class TestUser(BaseTest):
assert stored_obj.api_keys == [api_keys]
assert stored_obj.reset_tokens == [password_reset_token]
assert stored_obj.groups == [user_group_association]
assert stored_obj.repository_reviews == [repository_review]
assert collection_consists_of_objects(stored_obj.roles, private_user_role, non_private_user_role)
assert stored_obj.non_private_roles == [non_private_user_role]
@@ -948,12 +735,6 @@ def category(model, session):
yield from dbcleanup_wrapper(session, instance)
@pytest.fixture
def component(model, session):
instance = model.Component()
yield from dbcleanup_wrapper(session, instance)
@pytest.fixture
def galaxy_session(model, session):
instance = model.GalaxySession(session_key=get_unique_value())
@@ -992,13 +773,6 @@ def repository_metadata(model, session):
yield from dbcleanup_wrapper(session, instance)
@pytest.fixture
def repository_review(model, session, user):
instance = model.RepositoryReview()
instance.user = user
yield from dbcleanup_wrapper(session, instance)
@pytest.fixture
def repository_category_association(model, session, repository, category):
instance = model.RepositoryCategoryAssociation(repository, category)
@@ -1044,14 +818,6 @@ def user_role_association(model, session, user, role):
# Fixtures yielding factory functions.
@pytest.fixture
def component_review_factory(model):
def make_instance(*args, **kwds):
return model.ComponentReview(*args, **kwds)
return make_instance
@pytest.fixture
def group_role_association_factory(model):
def make_instance(*args, **kwds):
@@ -1068,14 +834,6 @@ def repository_metadata_factory(model):
return make_instance
@pytest.fixture
def repository_review_factory(model):
def make_instance(*args, **kwds):
return model.RepositoryReview(*args, **kwds)
return make_instance
@pytest.fixture
def role_factory(model):
def make_instance(*args, **kwds):