Skip to content
2 changes: 1 addition & 1 deletion api/app/events/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def post(self):

user_id = g.current_user["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_read_only):
return FORBIDDEN

if event_repository.exists_by_key(args['key']):
Expand Down
3 changes: 2 additions & 1 deletion api/app/users/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def user_info(user, roles):
'email': user.email,
'title': user.user_title,
'is_admin': user.is_admin,
'is_read_only': user.is_read_only,
'primary_language': user.user_primaryLanguage,
'roles': [{'event_id': event_role.event_id, 'role': event_role.role} for event_role in roles]
}
Expand Down Expand Up @@ -291,7 +292,7 @@ def get(self):

current_user = user_repository.get_by_id(current_user_id)

if current_user.is_admin:
if current_user.is_admin or current_user.is_read_only:
user = user_repository.get_by_id_with_response(user_id)
if user is None:
return USER_NOT_FOUND
Expand Down
24 changes: 23 additions & 1 deletion api/app/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class AppUser(db.Model, UserMixin):
password = db.Column(db.String(255), nullable=False)
active = db.Column(db.Boolean(), nullable=False)
is_admin = db.Column(db.Boolean(), nullable=False)
is_read_only = db.Column(db.Boolean(), nullable=False) # READ ONLY ACCESS
is_deleted = db.Column(db.Boolean(), nullable=False)
deleted_datetime_utc = db.Column(db.DateTime(), nullable=True)
verified_email = db.Column(db.Boolean(), nullable=True)
Expand All @@ -49,7 +50,8 @@ def __init__(self,
user_title,
password,
organisation_id,
is_admin=False):
is_admin=False,
is_read_only=False):
self.email = email
self.firstname = firstname
self.lastname = lastname
Expand All @@ -58,14 +60,21 @@ def __init__(self,
self.organisation_id = organisation_id
self.active = True
self.is_admin = is_admin
self.is_read_only = is_read_only
self.set_read_only()
self.is_deleted = False
self.deleted_datetime_utc = None
self.verified_email = False
self.agree_to_policy()


@property
def full_name(self):
return f"{self.firstname} {self.lastname}"

def set_read_only(self):
if self.is_read_only:
self.is_admin = True

def set_password(self, password):
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
Expand Down Expand Up @@ -103,6 +112,19 @@ def _has_admin_role(self, event_id, admin_role_name):
return True

return False

def _has_read_only_role(self, event_id):
if self.is_read_only:
return True

if self.event_roles is None:
return False

for event_role in self.event_roles:
if event_role.event_id == event_id and event_role.role == "read_only":
return True

return False

def is_event_admin(self, event_id):
return self._has_admin_role(event_id, 'admin')
Expand Down
17 changes: 10 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, isEventReadOnly, isRegistrationAdmin, isRegistrationVolunteer, isEventReviewer } from "./utils/user";
import { withTranslation } from 'react-i18next';
import { userService } from "./services/user";

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

<ul className="navbar-nav">
{this.props.user &&
{!isEventReadOnly(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 +75,8 @@ class EventNav extends Component {
</NavLink>
</li>
)}
{this.props.user && this.props.event && this.props.event.is_offer_open && (
{!isEventReadOnly(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 +88,8 @@ class EventNav extends Component {
</NavLink>
</li>
)}
{this.props.user &&
{!isEventReadOnly(this.props.user, this.props.event) &&
this.props.user &&
(
<li className="nav-item dropdown ">
<div
Expand Down Expand Up @@ -132,7 +135,7 @@ class EventNav extends Component {
</div>
</li>
)}
{isEventAdmin(this.props.user, this.props.event) && (
{isEventAdmin(this.props.user, this.props.event) && !isEventReadOnly(this.props.user, this.props.event) && (
<AdminMenu t={t} label="Event Admin">
<NavLink
to={`/${this.props.eventKey}/eventConfig`}
Expand Down Expand Up @@ -199,7 +202,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 @@ -232,7 +235,7 @@ 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)) && !isEventReadOnly(this.props.user, this.props.event) &&
this.props.event &&
this.props.event.is_registration_open && (
<li className="nav-item dropdown">
Expand Down
Loading