def reset(): "Reset the password for a user account and send email." if utils.http_GET(): email = flask.request.args.get("email") or "" email = email.lower() return flask.render_template("user/reset.html", email=email) elif utils.http_POST(): try: user = get_user(email=flask.request.form["email"]) if user is None: raise KeyError if user["status"] != constants.ENABLED: raise KeyError except KeyError: pass # Silent when no user found. else: with UserSaver(user) as saver: saver.set_password() send_password_code(user, "password reset") # Don't advertise whether user exists or not. utils.flash_message( "An email has been sent, if a user account with the given email address exists." ) return flask.redirect(flask.url_for("home"))
def create(pid, username): "Create a new review for the proposal for the given reviewer." proposal = anubis.proposal.get_proposal(pid) if proposal is None: return utils.error("No such proposal.", flask.url_for("home")) call = anubis.call.get_call(proposal["call"]) try: if not allow_create(proposal): raise ValueError("You may not create a review for the proposal.") user = anubis.user.get_user(username=username) if user is None: raise ValueError("No such user.") if user["username"] not in call["reviewers"]: raise ValueError("User is not a reviewer in the call.") review = get_reviewer_review(proposal, user) if review is not None: utils.flash_message("The review already exists.") return flask.redirect(flask.url_for(".display", iuid=review["_id"])) if proposal["user"] == user["username"]: raise ValueError( "Reviewer not allowed to review their own proposal.") with ReviewSaver(proposal=proposal, user=user) as saver: pass except ValueError as error: utils.flash_error(error) return flask.redirect( flask.url_for("reviews.call_reviewer", cid=proposal["call"], username=username))
def enable(username): "Enable the given user account." user = get_user(username=username) if user is None: return utils.error("No such user.", flask.url_for("home")) with UserSaver(user) as saver: saver.set_status(constants.ENABLED) saver.set_password() send_password_code(user, "enabled") utils.flash_message("User account enabled; email sent.") return flask.redirect(flask.url_for(".display", username=username))
def edit(username): "Edit the user. Or delete the user." user = get_user(username=username) if user is None: return utils.error("No such user.", flask.url_for("home")) if not allow_edit(user): return utils.error("Access to user edit not allowed.") if utils.http_GET(): return flask.render_template("user/edit.html", user=user, allow_change_role=allow_change_role(user)) elif utils.http_POST(): try: with UserSaver(user) as saver: if flask.g.am_admin: email = flask.request.form.get("email") saver.set_email(email, require=bool(email)) if allow_change_role(user): saver.set_role(flask.request.form.get("role")) saver.set_call_creator( utils.to_bool(flask.request.form.get("call_creator"))) saver.set_givenname(flask.request.form.get("givenname")) saver.set_familyname(flask.request.form.get("familyname")) saver.set_gender(flask.request.form.get("gender")) saver.set_birthdate(flask.request.form.get("birthdate")) saver.set_degree(flask.request.form.get("degree")) saver.set_affiliation( flask.request.form.get("affiliation") or flask.request.form.get("affiliation_other")) saver.set_postaladdress( flask.request.form.get("postaladdress")) saver.set_phone(flask.request.form.get("phone")) except ValueError as error: utils.flash_error(error) return flask.redirect( flask.url_for(".display", username=user["username"])) elif utils.http_DELETE(): if not allow_delete(user): return utils.error( "Cannot delete the user account; admin or not empty.", flask.url_for(".display", username=username), ) flask.g.db.delete(user) utils.flash_message(f"Deleted user {username}.") if flask.g.am_admin: return flask.redirect(flask.url_for(".all")) else: return flask.redirect(flask.url_for("home"))
def submit(pid): "Submit the proposal." proposal = get_proposal(pid) if proposal is None: return utils.error("No such proposal.", flask.url_for("home")) if utils.http_POST(): try: with ProposalSaver(proposal) as saver: saver.set_submitted() # Tests whether allowed or not. except ValueError as error: utils.flash_error(error) else: utils.flash_message("Proposal was submitted.") send_submission_email(proposal) return flask.redirect(flask.url_for(".display", pid=pid))
def reset_counter(cid): "Reset the counter of the call. Only if no proposals in it." call = get_call(cid) if not call: return utils.error("No such call.", flask.url_for("home")) if not allow_edit(call): return utils.error("You are not allowed to edit the call.") if utils.get_call_proposals_count(cid) != 0: return utils.error( "Cannot reset counter when there are" " proposals in the call." ) with CallSaver(call) as saver: saver["counter"] = None utils.flash_message("Counter for proposals in call reset.") return flask.redirect(flask.url_for(".display", cid=call["identifier"]))
def edit(cid): "Edit the call, or delete it." call = get_call(cid) if not call: return utils.error("No such call.", flask.url_for("home")) if not allow_edit(call): return utils.error("You are not allowed to edit the call.") if utils.http_GET(): return flask.render_template( "call/edit.html", call=call, allow_identifier_edit=allow_identifier_edit(call), ) elif utils.http_POST(): try: with CallSaver(call) as saver: saver.set_identifier(flask.request.form.get("identifier")) saver.set_title(flask.request.form.get("title")) saver["description"] = flask.request.form.get("description") saver["home_description"] = ( flask.request.form.get("home_description").strip() or None ) saver["opens"] = utils.normalize_datetime( flask.request.form.get("opens") ) saver["closes"] = utils.normalize_datetime( flask.request.form.get("closes") ) saver["reviews_due"] = utils.normalize_datetime( flask.request.form.get("reviews_due") ) saver.edit_access(flask.request.form) call = saver.doc except ValueError as error: utils.flash_error(error) return flask.redirect(flask.url_for(".display", cid=call["identifier"])) elif utils.http_DELETE(): if not allow_delete(call): return utils.error("You are not allowed to delete the call.") utils.delete(call) utils.flash_message(f"Deleted call {call['identifier']}:{call['title']}.") return flask.redirect( flask.url_for("calls.owner", username=flask.g.current_user["username"]) )
def create(pid): "Create a decision for the proposal." proposal = anubis.proposal.get_proposal(pid) if proposal is None: return utils.error("No such proposal.", flask.url_for("home")) try: if not allow_create(proposal): raise ValueError("You may not create a decision for the proposal.") decision = get_decision(proposal.get("decision")) if decision is not None: utils.flash_message("The decision already exists.") return flask.redirect( flask.url_for(".display", iuid=decision["_id"])) with DecisionSaver(proposal=proposal) as saver: pass decision = saver.doc with anubis.proposal.ProposalSaver(proposal) as saver: saver["decision"] = decision["_id"] except ValueError as error: utils.flash_error(error) return flask.redirect(flask.url_for(".display", iuid=decision["_id"]))
def edit(gid): "Edit the grant dossier." grant = get_grant(gid) if grant is None: return utils.error("No such grant.") call = anubis.call.get_call(grant["call"]) if utils.http_GET(): if not allow_edit(grant): return utils.error( "You are not allowed to edit this grant dossier.") return flask.render_template("grant/edit.html", grant=grant, call=call) elif utils.http_POST(): if not allow_edit(grant): return utils.error( "You are not allowed to edit this grant dossier.") try: with GrantSaver(doc=grant) as saver: saver.set_fields_values(call.get("grant", []), form=flask.request.form) except ValueError as error: return utils.error(error) if saver.repeat_changed: url = flask.url_for(".edit", gid=grant["identifier"]) else: url = flask.url_for(".display", gid=grant["identifier"]) return flask.redirect(url) elif utils.http_DELETE(): if not allow_delete(grant): return utils.error( "You are not allowed to delete this grant dossier.") proposal = anubis.proposal.get_proposal(grant["proposal"]) with anubis.proposal.ProposalSaver(proposal) as saver: saver["grant"] = None utils.delete(grant) utils.flash_message("Deleted grant dossier.") return flask.redirect( flask.url_for("proposal.display", pid=proposal["identifier"]))
def edit(iuid): "Edit the decision." try: decision = get_decision(iuid) except KeyError: return utils.error("No such decision.", flask.url_for("home")) proposal = anubis.proposal.get_proposal(decision["proposal"]) call = anubis.call.get_call(decision["call"]) if utils.http_GET(): if not allow_edit(decision): return utils.error("You are not allowed to edit this decision.") return flask.render_template("decision/edit.html", decision=decision, proposal=proposal, call=call) elif utils.http_POST(): if not allow_edit(decision): return utils.error("You are not allowed to edit this decision.") try: # NOTE: Repeat field has not been implemented for decision. with DecisionSaver(doc=decision) as saver: saver.set_verdict(form=flask.request.form) saver.set_fields_values(call["decision"], form=flask.request.form) except ValueError as error: return utils.error(error) return flask.redirect(flask.url_for(".display", iuid=decision["_id"])) elif utils.http_DELETE(): if not allow_delete(decision): return utils.error("You are not allowed to delete this decision.") with anubis.proposal.ProposalSaver(proposal) as saver: saver["decision"] = None utils.delete(decision) utils.flash_message("Deleted decision.") return flask.redirect( flask.url_for("proposal.display", pid=proposal["identifier"]))
def create(pid): "Create a grant dossier for the proposal." proposal = anubis.proposal.get_proposal(pid) if proposal is None: return utils.error("No such proposal.") try: if not allow_create(proposal): raise ValueError( "You may not create a grant dossier for the proposal.") grant = get_grant_proposal(pid) if grant is not None: utils.flash_message("The grant dossier already exists.") return flask.redirect( flask.url_for(".display", gid=grant["identifier"])) with GrantSaver(proposal=proposal) as saver: pass grant = saver.doc with anubis.proposal.ProposalSaver(proposal) as saver: saver["grant"] = grant["identifier"] except ValueError as error: utils.flash_error(error) return flask.redirect(flask.url_for(".display", gid=grant["identifier"]))
def password(): "Set the password for a user account, and login user." if utils.http_GET(): return flask.render_template( "user/password.html", username=flask.request.args.get("username"), code=flask.request.args.get("code"), ) elif utils.http_POST(): try: username = flask.request.form.get("username") or "" if not username: raise ValueError("No such user or wrong code.") user = get_user(username=username) if user is None: raise ValueError("No such user or wrong code.") if flask.g.am_admin: code = "" else: code = flask.request.form.get("code") or "" if user["password"] != f"code:{code}": raise ValueError("No such user or wrong code.") password = flask.request.form.get("password") or "" if len(password) < flask.current_app.config["MIN_PASSWORD_LENGTH"]: raise ValueError("Too short password.") except ValueError as error: return utils.error( error, flask.url_for(".password", username=username, code=code)) with UserSaver(user) as saver: saver.set_password(password) utils.flash_message("Password set.") if flask.g.am_admin: return flask.redirect(flask.url_for(".all")) else: do_login(username, password) return flask.redirect(flask.url_for("home"))
def edit(iuid): "Edit the review for the proposal." try: review = get_review(iuid) except KeyError: return utils.error("No such review.", flask.url_for("home")) proposal = anubis.proposal.get_proposal(review["proposal"]) call = anubis.call.get_call(review["call"]) if utils.http_GET(): if not allow_edit(review): return utils.error("You are not allowed to edit this review.") return flask.render_template("review/edit.html", review=review, proposal=proposal, call=call) elif utils.http_POST(): if not allow_edit(review): return utils.error("You are not allowed to edit this review.") try: # NOTE: Repeat field has not been implemented for review. with ReviewSaver(doc=review) as saver: saver.set_fields_values(call["review"], form=flask.request.form) except ValueError as error: return utils.error(error) return flask.redirect(flask.url_for(".display", iuid=review["_id"])) elif utils.http_DELETE(): if not allow_delete(review): return utils.error("You are not allowed to delete this review.") utils.delete(review) utils.flash_message("Deleted review.") return flask.redirect( flask.url_for("proposal.display", pid=review["proposal"]))
def register(): "Register a new user account." if utils.http_GET(): return flask.render_template("user/register.html", gdpr=utils.get_site_text("gdpr.md")) elif utils.http_POST(): try: with UserSaver() as saver: saver.set_username(flask.request.form.get("username")) saver.set_email(flask.request.form.get("email")) if utils.to_bool(flask.request.form.get("enable")): saver.set_status(constants.ENABLED) saver.set_role(constants.USER) saver.set_call_creator(False) saver.set_password() # Sets code. saver.set_givenname(flask.request.form.get("givenname")) saver.set_familyname(flask.request.form.get("familyname")) saver.set_gender(flask.request.form.get("gender")) saver.set_birthdate(flask.request.form.get("birthdate")) saver.set_degree(flask.request.form.get("degree")) saver.set_affiliation( flask.request.form.get("affiliation") or flask.request.form.get("affiliation_other")) saver.set_postaladdress( flask.request.form.get("postaladdress")) saver.set_phone(flask.request.form.get("phone")) user = saver.doc except ValueError as error: return utils.error(error, flask.url_for(".register")) # Directly enabled; send code to the user, if so instructed. if user["status"] == constants.ENABLED: if utils.to_bool(flask.request.form.get("send_email")): send_password_code(user, "registered") utils.flash_message( "User account created; an email with a link" " to set password has been sent.") else: utils.flash_message("User account created.") # Was set to 'pending'; send email to admins. else: utils.flash_message("User account created; an email will be sent" " when it has been enabled by the admin.") admins = get_users(role=constants.ADMIN, status=constants.ENABLED) recipients = [u["email"] for u in admins if u["email"]] site = flask.current_app.config["SITE_NAME"] title = f"{site} user account pending" url = flask.url_for(".display", username=user["username"], _external=True) text = f"To enable the user account, go to {url}\n\n" "/The Anubis system" utils.send_email(recipients, title, text) if flask.g.am_admin: return flask.redirect(flask.url_for("user.all")) else: return flask.redirect(flask.url_for("home"))
def edit(pid): "Edit the proposal." proposal = get_proposal(pid) if proposal is None: return utils.error("No such proposal.", flask.url_for("home")) call = anubis.call.get_call(proposal["call"]) if utils.http_GET(): if not allow_edit(proposal): return utils.error("You are not allowed to edit this proposal.") return flask.render_template("proposal/edit.html", proposal=proposal, call=call) elif utils.http_POST(): if not allow_edit(proposal): return utils.error("You are not allowed to edit this proposal.") try: with ProposalSaver(proposal) as saver: saver["title"] = flask.request.form.get("_title") or None saver.set_fields_values(call["proposal"], form=flask.request.form) except ValueError as error: return utils.error(error) # If a repeat field was changed, then redisplay edit page. if saver.repeat_changed: return flask.redirect( flask.url_for(".edit", pid=proposal["identifier"])) if flask.request.form.get("_save") == "submit": proposal = get_proposal(pid, refresh=True) # Get up-to-date info. try: with ProposalSaver(proposal) as saver: saver.set_submitted() # Tests whether allowed or not. except ValueError as error: utils.flash_error(error) else: utils.flash_message("Proposal saved and submitted.") send_submission_email(proposal) elif allow_submit(proposal) and not proposal.get("submitted"): utils.flash_warning("Proposal was saved but not submitted." " You must explicitly submit it!") return flask.redirect( flask.url_for(".display", pid=proposal["identifier"])) elif utils.http_DELETE(): if not allow_delete(proposal): return utils.error("You are not allowed to delete this proposal.") decision = anubis.decision.get_decision(proposal.get("decision")) if decision: utils.delete(decision) reviews = utils.get_docs_view("reviews", "proposal", proposal["identifier"]) for review in reviews: utils.delete(review) utils.delete(proposal) utils.flash_message(f"Deleted proposal {pid}.") if flask.g.am_admin or flask.g.am_staff: url = flask.url_for("proposals.call", cid=call["identifier"]) else: url = flask.url_for("proposals.user", username=proposal["user"]) return flask.redirect(url)