Skip to content
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

Added read_only role #1217

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
3 changes: 2 additions & 1 deletion api/app/events/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,9 @@ def post(self):
args = self.req_parser.parse_args()

user_id = g.current_user["id"]
event_id = request.args['id']
current_user = user_repository.get_by_id(user_id)
if not current_user.is_admin:
if not (current_user.is_admin or current_user.is_event_response_viewer(event_id) or current_user.is_event_response_editor(event_id)):
return FORBIDDEN

if event_repository.exists_by_key(args['key']):
Expand Down
19 changes: 19 additions & 0 deletions api/app/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def __init__(self,
self.deleted_datetime_utc = None
self.verified_email = False
self.agree_to_policy()


@property
def full_name(self):
Expand Down Expand Up @@ -103,7 +104,25 @@ def _has_admin_role(self, event_id, admin_role_name):
return True

return False

def _has_read_only_role(self, event_id):
if self.event_roles is None:
return False
for event_role in self.event_roles:
if self.is_admin and event_role.event_id == event_id and (event_role.role == "read_only" or event_role.role == "response_viewer" or event_role.role == "response_editor"):
return True

return False

def is_event_admin(self, event_id):
return self._has_admin_role(event_id, 'admin')

def is_event_response_viewer(self, event_id):
return self._has_read_only_role(event_id, 'response_viewer')

def is_event_response_editor(self, event_id):
return self._has_read_only_role(event_id, 'response_editor')

def is_event_admin(self, event_id):
return self._has_admin_role(event_id, 'admin')

Expand Down
22 changes: 15 additions & 7 deletions webapp/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import ReactGA from "react-ga";
import "./App.css";
import history from "./History";

import { isEventAdmin, isRegistrationAdmin, isRegistrationVolunteer, isEventReviewer } from "./utils/user";
import { isEventAdmin, isEventResponseViewerOnly, isEventResponseEditorOnly, isRegistrationAdmin, isRegistrationVolunteer, isEventReviewer } from "./utils/user";
import { withTranslation } from 'react-i18next';
import { userService } from "./services/user";

Expand Down Expand Up @@ -60,7 +60,9 @@ class EventNav extends Component {
} id="eventNavbar">

<ul className="navbar-nav">
{this.props.user &&
{!isEventResponseViewerOnly(this.props.user, this.props.event) &&
!isEventResponseEditorOnly(this.props.user, this.props.event) &&
this.props.user &&
this.props.event &&
this.props.event.is_application_open && (
<li className="nav-item">
Expand All @@ -74,7 +76,9 @@ class EventNav extends Component {
</NavLink>
</li>
)}
{this.props.user && this.props.event && this.props.event.is_offer_open && (
{!isEventResponseViewerOnly(this.props.user, this.props.event) &&
!isEventResponseEditorOnly(this.props.user, this.props.event) &&
this.props.user && this.props.event && this.props.event.is_offer_open && (
<li className="nav-item">
<NavLink
to={`/${this.props.eventKey}/offer`}
Expand All @@ -86,7 +90,9 @@ class EventNav extends Component {
</NavLink>
</li>
)}
{this.props.user &&
{!isEventResponseViewerOnly(this.props.user, this.props.event) &&
!isEventResponseEditorOnly(this.props.user, this.props.event) &&
this.props.user &&
(
<li className="nav-item dropdown ">
<div
Expand Down Expand Up @@ -132,7 +138,8 @@ class EventNav extends Component {
</div>
</li>
)}
{isEventAdmin(this.props.user, this.props.event) && (
{isEventAdmin(this.props.user, this.props.event) && !isEventResponseViewerOnly(this.props.user, this.props.event) &&
!isEventResponseEditorOnly(this.props.user, this.props.event) && (
<AdminMenu t={t} label="Event Admin">
<NavLink
to={`/${this.props.eventKey}/eventConfig`}
Expand Down Expand Up @@ -206,7 +213,7 @@ class EventNav extends Component {
{t('Review Form')}
</NavLink>
</AdminMenu>
)}
)}
{isEventReviewer(this.props.user, this.props.event) &&
this.props.event &&
this.props.event.is_review_open && (
Expand Down Expand Up @@ -239,7 +246,8 @@ class EventNav extends Component {
</div>
</li>
)}
{(isRegistrationAdmin(this.props.user, this.props.event) || isRegistrationVolunteer(this.props.user, this.props.event)) &&
{(isRegistrationAdmin(this.props.user, this.props.event) || isRegistrationVolunteer(this.props.user, this.props.event)) && !isEventResponseViewerOnly(this.props.user, this.props.event) &&
!isEventResponseEditorOnly(this.props.user, this.props.event) &&
this.props.event &&
this.props.event.is_registration_open && (
<li className="nav-item dropdown">
Expand Down
72 changes: 36 additions & 36 deletions webapp/src/pages/ResponseList/components/ResponseListComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { reviewService } from '../../../services/reviews/review.service';
import { ConfirmModal } from "react-bootstrap4-modal";
import TagSelectorDialog from '../../../components/TagSelectorDialog';
import { createColClassName } from "../../../utils/styling/styling";
import { isEventResponseViewerOnly } from '../../../utils/user';

class ResponseListComponent extends Component {
constructor(props) {
Expand Down Expand Up @@ -373,42 +374,41 @@ class ResponseListComponent extends Component {
/>
</div>
</div>

<form>
<div className="card">
<p className="h4 text-center mb-4">{t("Assign Reviewer")}</p>

<div className="row">
<p className="h6 text-center mb-3">{t("Filter the table above then enter a reviewer's email to assign them the filtered rows (the reviewer must already have a Baobab account)")}</p>

<div className="col-md-10 pr-2">
<FormTextBox
id={"newReviewEmail"}
name={'newReviewEmail'}
placeholder={t("Email")}
onChange={this.handleChange}
value={newReviewerEmail}
key={"newReviewEmail"} />
</div>
<div className="col-md-2 pr-2">
<button
className="btn btn-primary btn-block"
onClick={() => { this.assignReviewer() }}
disabled={!newReviewerEmail}>
{t("Assign")}
</button>
</div>

{reviewerAssignError && <span className="alert alert-danger">
{JSON.stringify(this.state.reviewerAssignError)}
</span>}

{reviewerAssignSuccess && <span className="alert alert-success">
<Trans i18nKey="reviewsAssigned">Assigned {{numReviewsAssigned}} reviews to {{assignedReviewerEmail}}</Trans>
</span>}
</div>
</div>
</form>

{(!isEventResponseViewerOnly(this.props.user && this.props.event) &&
<form>
<div className="card">
<p className="h4 text-center mb-4">{t("Assign Reviewer")}</p>
<div className="row">
<p className="h6 text-center mb-3">{t("Filter the table above then enter a reviewer's email to assign them the filtered rows (the reviewer must already have a Baobab account)")}</p>

<div className="col-md-10 pr-2">
<FormTextBox
id={"newReviewEmail"}
name={'newReviewEmail'}
placeholder={t("Email")}
onChange={this.handleChange}
value={newReviewerEmail}
key={"newReviewEmail"} />
</div>
<div className="col-md-2 pr-2">
<button
className="btn btn-primary btn-block"
onClick={() => { this.assignReviewer() }}
disabled={!newReviewerEmail}>
{t("Assign")}
</button>
</div>
{reviewerAssignError && <span className="alert alert-danger">
{JSON.stringify(this.state.reviewerAssignError)}
</span>}
{reviewerAssignSuccess && <span className="alert alert-success">
<Trans i18nKey="reviewsAssigned">Assigned {{numReviewsAssigned}} reviews to {{assignedReviewerEmail}}</Trans>
</span>}
</div>
</div>
</form>
)}

<TagSelectorDialog
tags={this.state.filteredTags}
Expand Down
Loading