-
Notifications
You must be signed in to change notification settings - Fork 176
frontend: add direct link to request if user has access #3251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4e2d526
e13c5ab
a49a491
ce69b74
a81f346
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
|
|
||
| from flask import abort, current_app, g, redirect, render_template, request, url_for | ||
| from flask_login import current_user | ||
| from flask_principal import AnonymousIdentity | ||
| from invenio_base.utils import obj_or_import_string | ||
| from invenio_communities.communities.resources.serializer import ( | ||
| UICommunityJSONSerializer, | ||
|
|
@@ -28,7 +29,10 @@ | |
| from invenio_rdm_records.records.systemfields.access.access_settings import ( | ||
| AccessSettings, | ||
| ) | ||
| from invenio_rdm_records.requests import CommunityInclusion, CommunitySubmission | ||
| from invenio_rdm_records.resources.serializers import UIJSONSerializer | ||
| from invenio_requests.proxies import current_requests_service | ||
| from invenio_search.api import dsl | ||
| from invenio_stats.proxies import current_stats | ||
| from invenio_users_resources.proxies import current_user_resources | ||
| from marshmallow import ValidationError | ||
|
|
@@ -99,6 +103,43 @@ def get_record_community(record): | |
| return None, None | ||
|
|
||
|
|
||
| def get_record_requests(record, identity): | ||
| """Return all requests that concern this record. | ||
|
|
||
| Output: {<Community-UUID>: <Request-UUID>} | ||
| """ | ||
| can_review = current_rdm_records.records_service.check_permission( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be "can_preview"? This would also include the links with guest token who would have access.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you explain why can preview? From what I understand can preview refers to people who can preview a draft, whereas review is people who can review the record (i.e. see the request)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to update our docs then ahah https://help.zenodo.org/docs/share/about/ |
||
| identity, "review", record=record._record | ||
| ) | ||
| if not can_review: | ||
| return {} | ||
|
|
||
| if type(identity) is AnonymousIdentity: | ||
| return {} # secret link users do not have permissions to search requests | ||
|
|
||
| record_requests = current_requests_service.search( | ||
| identity, | ||
| extra_filter=dsl.Q( | ||
| "bool", | ||
| must=[ | ||
| dsl.Q("term", **{"topic.record": record["id"]}), | ||
| dsl.Q( | ||
| "terms", | ||
| **{ | ||
| "type": [ | ||
| CommunityInclusion.type_id, | ||
| CommunitySubmission.type_id, | ||
| ] | ||
| }, | ||
| ), | ||
| ], | ||
| ), | ||
| params={"sort": "oldest"}, | ||
| ) | ||
|
|
||
| return {r["receiver"]["community"]: r["id"] for r in record_requests} | ||
|
|
||
|
|
||
| class PreviewFile: | ||
| """Preview file implementation for InvenioRDM. | ||
|
|
||
|
|
@@ -238,6 +279,8 @@ def record_detail( | |
| ) | ||
| theme = resolved_community_ui.get("theme", {}) if resolved_community else None | ||
|
|
||
| record_requests = get_record_requests(record, g.identity) | ||
|
|
||
| return render_community_theme_template( | ||
| current_app.config.get("APP_RDM_RECORD_LANDING_PAGE_TEMPLATE"), | ||
| theme=theme, | ||
|
|
@@ -267,6 +310,7 @@ def record_detail( | |
| is_draft=is_draft, | ||
| community=resolved_community, | ||
| community_ui=resolved_community_ui, | ||
| record_requests=record_requests, | ||
| external_resources=get_external_resources(record), | ||
| user_avatar=avatar, | ||
| record_deletion=record_deletion, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,8 @@ import { | |
|
|
||
| export class RecordCommunitiesList extends Component { | ||
| render() { | ||
| const { communities, loading, error, maxDisplayedCommunities } = this.props; | ||
| const { communities, loading, error, maxDisplayedCommunities, recordRequests } = | ||
| this.props; | ||
| let Element = null; | ||
|
|
||
| if (loading) { | ||
|
|
@@ -56,49 +57,71 @@ export class RecordCommunitiesList extends Component { | |
| } else if (communities?.length > 0) { | ||
| const communityItems = communities | ||
| ?.slice(0, maxDisplayedCommunities) | ||
| .map((community) => ( | ||
| <Grid key={community.id}> | ||
| <Grid.Row verticalAlign="middle"> | ||
| <Grid.Column width={2}> | ||
| <Image wrapped size="mini" src={community.links.logo} alt="" /> | ||
| </Grid.Column> | ||
| <Grid.Column width={14}> | ||
| <Item.Content> | ||
| <Item.Header className="ui"> | ||
| <Header as="a" href={community.links.self_html} size="small"> | ||
| {community.metadata.title} | ||
| {/* Show the icon for communities allowing children, and for subcommunities */} | ||
| {(community.children?.allow || | ||
| community.parent !== undefined) && ( | ||
| <p className="ml-5 display-inline-block"> | ||
| <Popup | ||
| content="Verified community" | ||
| trigger={ | ||
| <Icon | ||
| size="small" | ||
| color="green" | ||
| name="check circle outline" | ||
| /> | ||
| } | ||
| position="top center" | ||
| /> | ||
| </p> | ||
| .map((community) => { | ||
| const viewRequest = community.id in recordRequests; | ||
| return ( | ||
| <Grid key={community.id}> | ||
| <Grid.Row verticalAlign="middle"> | ||
| <Grid.Column width={3}> | ||
| <Image wrapped size="mini" src={community.links.logo} alt="" /> | ||
| </Grid.Column> | ||
| <Grid.Column width={13} className="pl-0"> | ||
| <Item.Content> | ||
| <Item.Header className="ui"> | ||
| <Header as="a" href={community.links.self_html} size="small"> | ||
| {community.metadata.title} | ||
| {/* Show the icon for communities allowing children, and for subcommunities */} | ||
| {(community.children?.allow || | ||
| community.parent !== undefined) && ( | ||
| <p className="ml-5 display-inline-block"> | ||
| <Popup | ||
| content="Verified community" | ||
| trigger={ | ||
| <Icon | ||
| size="small" | ||
| color="green" | ||
| name="check circle outline" | ||
| /> | ||
| } | ||
| position="top center" | ||
| /> | ||
| </p> | ||
| )} | ||
| </Header> | ||
| {community.parent && ( | ||
| <HeaderSubheader> | ||
| {i18next.t("Part of")}{" "} | ||
| <a href={`/communities/${community.parent.slug}`}> | ||
| {i18next.t(community.parent.metadata.title)} | ||
| </a> | ||
| </HeaderSubheader> | ||
| )} | ||
| </Header> | ||
| {community.parent && ( | ||
| <HeaderSubheader> | ||
| {i18next.t("Part of")}{" "} | ||
| <a href={`/communities/${community.parent.slug}`}> | ||
| {i18next.t(community.parent.metadata.title)} | ||
| </a> | ||
| </HeaderSubheader> | ||
| )} | ||
| </Item.Header> | ||
| </Item.Content> | ||
| </Grid.Column> | ||
| </Grid.Row> | ||
| </Grid> | ||
| )); | ||
| {viewRequest && ( | ||
| <div> | ||
| <small> | ||
| <b> | ||
| <a | ||
| // building request link as the self_html of the request is | ||
| // /requests/<uuid> which doesn't resolve as missing | ||
| // /communities/ or /me/. We prefer /communities/ here | ||
| href={`${community.links.self_html}requests/${ | ||
| recordRequests[community.id] | ||
|
Comment on lines
+107
to
+108
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we would also need to propagate guest token here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can guests see requests? I thought guest tokens are for previewing a draft/viewing restricted files/editing a draft
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, see the screenshot above ^^ |
||
| }`} | ||
| > | ||
| <Icon name="discussions" className="mr-5" /> | ||
| {i18next.t("View comments")} | ||
| </a> | ||
| </b> | ||
| </small> | ||
| </div> | ||
| )} | ||
| </Item.Header> | ||
| </Item.Content> | ||
| </Grid.Column> | ||
| </Grid.Row> | ||
| </Grid> | ||
| ); | ||
| }); | ||
|
|
||
| Element = ( | ||
| <> | ||
|
|
@@ -116,10 +139,12 @@ RecordCommunitiesList.propTypes = { | |
| communities: PropTypes.array, | ||
| loading: PropTypes.bool, | ||
| error: PropTypes.string, | ||
| recordRequests: PropTypes.object, | ||
| }; | ||
|
|
||
| RecordCommunitiesList.defaultProps = { | ||
| communities: undefined, | ||
| loading: false, | ||
| error: "", | ||
| recordRequests: {}, | ||
| }; | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the default needed, I assume the
record_requestsin this case would be empty when passed, so maybe we don't need itUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, it is passed as
undefinedto the HTML in the case of the review page for example. This is a safeguard as otherwise the page doesn't render (undefined is not valid json)