diff --git a/conditional/blueprints/housing.py b/conditional/blueprints/housing.py index 7326309d..f7382ff5 100644 --- a/conditional/blueprints/housing.py +++ b/conditional/blueprints/housing.py @@ -11,6 +11,7 @@ from conditional.util.ldap import ldap_get_member from conditional.util.ldap import ldap_get_roomnumber from conditional.util.ldap import ldap_get_current_students +from conditional.util.ldap import ldap_set_active from conditional.util.flask import render_template @@ -118,6 +119,8 @@ def change_room_numbers(rmnumber): account = ldap_get_member(occupant) account.roomNumber = rmnumber log.info('api', action='%s assigned to room %s' % (occupant, rmnumber)) + ldap_set_active(account) + log.info('api', action='%s marked as active because of room assignment' % occupant) # Delete any old occupants that are no longer in room. for old_occupant in [account for account in current_students if ldap_get_roomnumber(account) == str(rmnumber) @@ -138,3 +141,24 @@ def get_occupants(rmnumber): occupants = [account.uid for account in current_students if ldap_get_roomnumber(account) == str(rmnumber)] return jsonify({"room": rmnumber, "occupants": occupants}), 200 + + +@housing_bp.route('/housing', methods=['DELETE']) +def clear_all_rooms(): + log = logger.new(user_name=request.headers.get("x-webauth-user"), + request_id=str(uuid.uuid4())) + log.info('api', action='clear all room numbers') + + username = request.headers.get('x-webauth-user') + account = ldap_get_member(username) + + if not ldap_is_eval_director(account): + return "must be eval director", 403 + # Get list of current students. + current_students = ldap_get_current_students() + + # Find the current occupants and clear them. + for occupant in current_students: + log.info('api', action='remove room %s from %s' % (occupant.roomNumber, occupant.uid)) + occupant.roomNumber = None + return jsonify({"success": True}), 200 diff --git a/conditional/blueprints/member_management.py b/conditional/blueprints/member_management.py index 161c998e..abb047fb 100644 --- a/conditional/blueprints/member_management.py +++ b/conditional/blueprints/member_management.py @@ -33,8 +33,11 @@ from conditional.util.ldap import ldap_set_active from conditional.util.ldap import ldap_set_inactive from conditional.util.ldap import ldap_set_housingpoints +from conditional.util.ldap import ldap_set_current_student +from conditional.util.ldap import ldap_set_non_current_student from conditional.util.ldap import ldap_get_active_members from conditional.util.ldap import ldap_get_member +from conditional.util.ldap import ldap_get_current_students from conditional.util.ldap import _ldap_add_member_to_group as ldap_add_member_to_group from conditional.util.ldap import _ldap_remove_member_from_group as ldap_remove_member_from_group from conditional.util.ldap import _ldap_is_member_of_group as ldap_is_member_of_group @@ -549,7 +552,7 @@ def introductory_project_submit(): def get_member(uid): log = logger.new(user_name=request.headers.get("x-webauth-user"), request_id=str(uuid.uuid4())) - log.info('api', action='submit introductory project results') + log.info('api', action="get {}'s information".format(uid)) username = request.headers.get('x-webauth-user') account = ldap_get_member(username) @@ -565,3 +568,66 @@ def get_member(uid): } return jsonify(account_dict), 200 + +@member_management_bp.route('/manage/active', methods=['DELETE']) +def clear_active_members(): + log = logger.new(user_name=request.headers.get("x-webauth-user"), + request_id=str(uuid.uuid4())) + log.info('api', action='clear active group') + + username = request.headers.get('x-webauth-user') + account = ldap_get_member(username) + + if not ldap_is_eval_director(account): + return "must be eval director", 403 + # Get the active group. + members = ldap_get_active_members() + + # Clear the active group. + for account in members: + log.info('api', action='remove %s from active status' % account.uid) + ldap_set_inactive(account) + return jsonify({"success": True}), 200 + + +@member_management_bp.route('/manage/current/', methods=['POST', 'DELETE']) +def remove_current_student(uid): + log = logger.new(user_name=request.headers.get("x-webauth-user"), + request_id=str(uuid.uuid4())) + + + username = request.headers.get('x-webauth-user') + account = ldap_get_member(username) + + if not ldap_is_eval_director(account): + return "must be eval director", 403 + + member = ldap_get_member(uid) + if request.method == 'DELETE': + log.info('api', action='remove {} from current_student'.format(uid)) + ldap_set_non_current_student(member) + elif request.method == 'POST': + log.info('api', action='add {} to current_student'.format(uid)) + ldap_set_current_student(member) + return jsonify({"success": True}), 200 + + +@member_management_bp.route('/manage/new', methods=['GET']) +def new_year(): + log = logger.new(user_name=request.headers.get("x-webauth-user"), + request_id=str(uuid.uuid4())) + log.info('api', action='show new year page') + + username = request.headers.get('x-webauth-user') + account = ldap_get_member(username) + + if not ldap_is_eval_director(account): + return "must be eval director", 403 + + current_students = ldap_get_current_students() + + + return render_template(request, + 'new_year.html', + username=username, + current_students=current_students) diff --git a/conditional/templates/member_management.html b/conditional/templates/member_management.html index 3c7c7135..6235978f 100644 --- a/conditional/templates/member_management.html +++ b/conditional/templates/member_management.html @@ -27,13 +27,16 @@

Administration

Intro Accounts
{% if is_eval_director %} -
+
Site Lockdown
+ {% endif %}
diff --git a/conditional/templates/new_year.html b/conditional/templates/new_year.html new file mode 100644 index 00000000..b8d01273 --- /dev/null +++ b/conditional/templates/new_year.html @@ -0,0 +1,49 @@ +{% extends "nav.html" %} +{% block title %} +New Year Guide +{% endblock %} +{% block body %} +
+
+

Welcome!

+

Is it that time of year already? Before we get started, please be careful and ready everything before continuing. Some actions taken on the next few steps can be detrimental if followed in the middle of the year. Once you are ready to proceed, click 'Begin' below.

+ Begin +
+ + + +
+{% endblock %} diff --git a/conditional/util/ldap.py b/conditional/util/ldap.py index cbe140b1..443c877d 100644 --- a/conditional/util/ldap.py +++ b/conditional/util/ldap.py @@ -121,6 +121,18 @@ def ldap_set_inactive(account): ldap_get_member.cache_clear() +def ldap_set_current_student(account): + _ldap_add_member_to_group(account, 'current_student') + ldap_get_current_students.cache_clear() + ldap_get_member.cache_clear() + + +def ldap_set_non_current_student(account): + _ldap_remove_member_from_group(account, 'current_student') + ldap_get_current_students.cache_clear() + ldap_get_member.cache_clear() + + def ldap_get_roomnumber(account): try: return account.roomNumber diff --git a/frontend/javascript/modules/newYear.js b/frontend/javascript/modules/newYear.js new file mode 100644 index 00000000..0d8ba6ae --- /dev/null +++ b/frontend/javascript/modules/newYear.js @@ -0,0 +1,80 @@ +import FetchUtil from '../utils/fetchUtil'; +import Exception from "../exceptions/exception"; +import FetchException from "../exceptions/fetchException"; +import sweetAlert from "../../../node_modules/bootstrap-sweetalert/dev/sweetalert.es6.js"; // eslint-disable-line max-len + +export default class NewYear { + constructor(link) { + this.link = link; + this.step = this.link.dataset.step; + this.uid = this.link.dataset.uid; + + this.endpoints = { + housing: '/housing', + active: '/manage/active', + current: '/manage/current/' + }; + + this.render(); + } + render() { + this.link.addEventListener('click', e => { + e.preventDefault(); + + if (this.step === "welcome") { + $('#new-welcome').fadeOut(() => { + $("#new-clear").fadeIn(); + }); + } else if (this.step === "clear") { + FetchUtil.fetchWithWarning(this.endpoints.active, { + method: 'DELETE', + warningText: "This will clear active members and room assignments!", + successText: "Data successfully cleared."}, () => { + fetch(this.endpoints.housing, { + method: 'DELETE' + }) + .then($('#new-clear').fadeOut(() => { + $("#new-current").fadeIn(); + }) + ).catch(error => { + sweetAlert("Uh oh...", "We're having trouble submitting that " + + "action right now. Please try again later.", "error"); + throw new Exception(FetchException.REQUEST_FAILED, error); + }); + }); + } else if (this.uid) { + if ($('#rem-' + this.uid).is(":visible")) { + fetch(this.endpoints.current + this.uid, { + method: 'DELETE' + }).then(() => { + $('#rem-' + this.uid).hide(); + $('#add-' + this.uid).show(); + var userRow = $('#row-' + this.uid)[0]; + userRow.style.setProperty("text-decoration", "line-through"); + }).catch(error => { + sweetAlert("Uh oh...", "We're having trouble submitting that " + + "action right now. Please try again later.", "error"); + throw new Exception(FetchException.REQUEST_FAILED, error); + }); + } else { + fetch(this.endpoints.current + this.uid, { + method: 'POST' + }).then(() => { + $('#add-' + this.uid).hide(); + $('#rem-' + this.uid).show(); + var lineRow = $('#row-' + this.uid)[0]; + lineRow.style.setProperty("text-decoration", "none"); + }).catch(error => { + sweetAlert("Uh oh...", "We're having trouble submitting that " + + "action right now. Please try again later.", "error"); + throw new Exception(FetchException.REQUEST_FAILED, error); + }); + } + } else if (this.step === "current") { + $('#new-current').fadeOut(function() { + $("#new-housing").fadeIn(); + }); + } + }); + } +} diff --git a/frontend/stylesheets/pages/_management.scss b/frontend/stylesheets/pages/_management.scss index f92d0a9c..23e70bc1 100644 --- a/frontend/stylesheets/pages/_management.scss +++ b/frontend/stylesheets/pages/_management.scss @@ -1,9 +1,17 @@ .switch-label { - display: inline-block; - padding: 40px 10px; + display: block; + padding: 17px 10px 10px; text-align: center; } +.btn-new-year { + margin-top: 30px; +} + +.btn-new-next { + margin: 30px 0; +} + .upload-title { padding-top: 20px; height: 55px; diff --git a/frontend/stylesheets/partials/_global.scss b/frontend/stylesheets/partials/_global.scss index b4d32def..ec9be224 100644 --- a/frontend/stylesheets/partials/_global.scss +++ b/frontend/stylesheets/partials/_global.scss @@ -88,3 +88,7 @@ tr { float: none; vertical-align: middle; } + +.hidden { + display: none; +}