def dashboard(user_url_segment=None): if user_url_segment is None: target_user = UserData.get_current_user_data() else: target_user = UserData.get_from_url_segment(user_url_segment) if target_user is None: template_values = { 'target_user': user_url_segment, } return render_jinja_template("noprofile.html", template_values), 404 if target_user.username != user_url_segment: return redirect('/dashboard/{0}'.format(target_user.username)) # If looking at the current user's profile, hilight the users name in the # nav bar if target_user == UserData.get_current_user_data(): return redirect('/'.format(target_user.username)) else: active = None template_values = { 'target_user': target_user, } return render_jinja_template("dashboard.html", template_values)
def get(self): user_filter = request.args.get("filter", "both") if user_filter not in ["active", "inactive", "both"]: raise Exception(user_filter + " is not a valid filter value") if user_filter == "active": q = UserData.query().filter(UserData.active == True) elif user_filter == "inactive": q = UserData.query().filter(UserData.active == False) else: q = UserData.query() q = q.order(UserData.first_name) data = {"users": []} for u in q: # TODO (phillip): code to create a user json object is duplicated in multiple # places. I should keep it in one spot (maybe UserData) data["users"].append( { "fname": u.first_name, "lname": u.last_name, "active": u.active, "grad_year": u.graduation_year, "grad_semester": u.graduation_semester, "classification": u.classification, "permissions": u.user_permissions, "user_id": u.user_id, } ) return jsonify(**data)
def index(): template_values = { 'active_page': 'home', 'target_user': UserData.get_current_user_data(), } if UserData.get_current_user_data(): return render_jinja_template("dashboard.html", template_values) else: return render_jinja_template("index.html", template_values)
def render_jinja_template(name, context=None): """ Renders a jinja template witha given context This function will also add global template values. Args: name: The name of the jinja template to be rendered context (dict): A dictionary of values to pass to the template """ # We want to make sure all templates have this function, but we also # need to avoid circular dependencies so import this here. from permissions import check_perms template_values = { 'user_data': UserData.get_current_user_data(), 'login_url': url_for('login', next=request.path), 'logout_url': users.create_logout_url("/"), 'check_perms': check_perms, 'is_admin': users.is_current_user_admin(), } if context != None: template_values.update(context) return render_template(name, **template_values)
def post(self, user_id): user = UserData.get_user_from_id(user_id) if not user: raise Exception("I don't know that person") #TODO (phillip): The flow of this code looks more complicated and confusing than it # needs to be. Try to clean it up data = request.form p = None for exc in user.point_exceptions: if exc.point_category == data['point_category']: p = exc if not p: p = PointException() p.point_category = data.get('point_category', type=str) p.points_needed = data.get('points_needed', type=int) user.point_exceptions.append(p) else: p.points_needed = data.get('points_needed', type=int) user.put() response = jsonify() response.status_code = 201 response.headers['location'] = "/api/users/" + user.user_id + \ "/point-exceptions/" + \ str(user.point_exceptions.index(p)) return response
def get(self, user_id): user = UserData.get_user_from_id(user_id) data = { u'permissions': user.user_permissions, } return jsonify(**data)
def put(self): data = request.form user_data = UserData.get_from_username(data['username']) if not user_data: raise Exception("I don't know that person") event = Event.get_from_name(data['event_name']) if not event: raise Exception("I don't know that event") point_record = PointRecord.query(PointRecord.event_name == event.name, PointRecord.username == user_data.username).get() # TODO (phillip): this might allow me to not create new records every time a # new event or user is created because a record will be created when # the client tries to modify a record that should exist # Create a point record if one does not exist if not point_record: # TODO (phillip): does this work with the user key as the ancestor? point_record = PointRecord(parent=user_data.key) point_record.event_name = event.name point_record.username = user_data.username point_record.points_earned = float(data['points-earned']) point_record.put() # TODO (phillip): A put request (and really any other request that creates or # updates an object) should return the new representation of that # object so clients don't need to make more API calls response = jsonify() response.status_code = 204 return response
def permissions(): template_values = { 'active_page': "permissions", 'users': UserData.query().order(UserData.first_name), } return render_jinja_template("permissions.html", template_values)
def put(self, user_id): """ Updates the user profile information This method can only be called by the user being updated or an officer. We do not need to protect against the user changing their point exceptions in this method because the method does not update the point exceptions. """ user = UserData.get_user_from_id(user_id) if not user: raise Exception("I don't know that person") data = request.form user.first_name = data["fname"] user.last_name = data["lname"] if data["active"] == "true": user.active = True else: user.active = False user.classification = data["classification"] user.graduation_semester = data["grad_semester"] user.graduation_year = data.get("grad_year", type=int) user.put() # TODO (phillip): A put request (and really any other request that creates or # updates an object) should return the new representation of that # object so clients don't need to make more API calls response = jsonify() response.status_code = 204 # TODO (phillip): I believe only POST requests need to return this header response.headers["location"] = "/api/users/" + str(user.user_id) return response
def members(): template_values = { 'active_page': 'members', 'users': UserData.query().order(UserData.first_name), } return render_jinja_template("members.html", template_values)
def delete(self, user_id, perm): user = UserData.get_user_from_id(user_id) if perm not in user.user_permissions: response = jsonify(message="Resource does not exist") response.status_code = 404 return response user.user_permissions.remove(perm) user.put()
def get(self, user_id): user = UserData.get_user_from_id(user_id) data = { "point_exceptions": [{ "point_category": exc.point_category, "points_needed": exc.points_needed, } for exc in user.point_exceptions], } return jsonify(**data)
def delete(self, user_id, index): user = UserData.get_user_from_id(user_id) if not user: raise Exception("I don't know that person") if index > len(user.point_exceptions)-1: response = jsonify(message="Resource does not exist") response.status_code = 404 return response del user.point_exceptions[index] user.put()
def postlogin(): """ Handler for just after a user has logged in This takes care of making sure the user has properly setup their account. """ next_url = request.args.get("next", "/") user_data = UserData.get_current_user_data() if not user_data: # Need to create a user account signup_url = url_for("signup", next=next_url) return redirect(signup_url) else: return redirect(next_url)
def profile(user_url_segment): target_user = UserData.get_from_url_segment(user_url_segment) if target_user is None: template_values = { 'target_user': user_url_segment, } return render_jinja_template("noprofile.html", template_values), 404 if target_user.username != user_url_segment: return redirect('/profile/{0}'.format(target_user.username)) # If looking at the current user's profile, hilight the users name in the # nav bar if target_user == UserData.get_current_user_data(): active = 'profile' else: active = None template_values = { 'active_page': active, 'target_user': target_user, } return render_jinja_template("profile.html", template_values)
def wrapper(*args, **kwargs): current_user = UserData.get_current_user_data() if not current_user: template_values = { u'message': u"Not logged in", u'html_template': u"nologin.html", } return build_response(output_format, template_values) missing_perms = [] if 'user_url_segment' in kwargs: other_user_url_segment = kwargs['user_url_segment'] elif 'user_id' in kwargs: other_user_url_segment = kwargs['user_id'] else: other_user_url_segment = None if other_user_url_segment: other_user = UserData.get_from_url_segment(other_user_url_segment) else: other_user = None for p in perms: if not check_perms(current_user, p, other_user): missing_perms.append(p) template_values = { u'message': "Don't have permission", u'html_template': "nopermission.html", u'perms': missing_perms, } if len(missing_perms) > 0 and logic == 'and': return build_response(output_format, template_values) elif len(missing_perms) == len(perms) and logic == 'or': return build_response(output_format, template_values) return f(*args, **kwargs)
def post(self, user_id): user = UserData.get_user_from_id(user_id) data = request.form perm = data['permission'] if perm not in user.user_permissions: # TODO (phillip): an officer could theoretically give themselves 'admin' # privileges using this function. They wouldn't get actual google # admin privileges but it would fool my permissions system user.user_permissions.append(perm) user.put() response = jsonify() response.status_code = 201 response.headers['location'] = "/api/users/" + user.user_id + \ "/permissions/" + perm return response
def get(self, user_id, index): user = UserData.get_user_from_id(user_id) if not user: raise Exception("I don't know that person") if index > len(user.point_exceptions)-1: response = jsonify(message="Resource does not exist") response.status_code = 404 return response exc = user.point_exceptions[index] data = { "point_category": exc.point_category, "points_needed": exc.points_needed, } return jsonify(**data)
def get(self, user_id): user = UserData.get_user_from_id(user_id) data = { "active": user.active, "classification": user.classification, "grad_year": user.graduation_year, "grad_semester": user.graduation_semester, "fname": user.first_name, "lname": user.last_name, "permissions": user.user_permissions, "user_id": user.user_id, "point_exceptions": [ {"point_category": exc.point_category, "points_needed": exc.points_needed} for exc in user.point_exceptions ], } return jsonify(**data)
def post(self): """ Adds a new user This does not need any extra security because it only changes the information for the currently logged in google user. If there is no google user logged in an error is thrown. """ # TODO (phillip): this method throws generic exceptions that really can't be # properly handled by the client in a user-friendly way. I should # really return error codes here so the client knows what went wrong # other than a generic server error data = request.form user = users.get_current_user() if not user: raise Exception("Where is the user?") # NOTE: I am using the user.user_id() as the UserData id so that I can # query for UserData with strong consistency. I believe this works as # intended and the only issue I can think of is if I decide to allow # logging in from something other than a google account (which would mean # the user is not connected to a google user with a user_id) user_data = UserData(id=user.user_id()) user_data.user = user user_data.user_id = user.user_id() if data["fname"] == "": raise Exception("The first name was empty") user_data.first_name = data["fname"] if data["lname"] == "": raise Exception("The first name was empty") # TODO (phillip): A duplicate username should produce a better error than a 500 other_users = UserData.query() other_user = None for user in other_users: if user.username == data["fname"] + data["lname"]: other_user = user if other_user is not None: raise Exception("There is already a user with that name.") user_data.last_name = data["lname"] user_data.graduation_year = int(data["grad_year"]) user_data.graduation_semester = data["grad_semester"] user_data.classification = data["classification"] user_data.active = True user_data.user_permissions = ["user"] user_data.put() # TODO (phillip): find a better way that doesn't require you to remember to add # this line every single time you want to create a UserData object. # Create the necessary point records user_data.populate_records() response = jsonify() response.status_code = 201 response.headers["location"] = "/api/users/" + str(user_data.user_id) return response
def get(self, user_id): output = {u"categories": {}} user = UserData.get_user_from_id(user_id) point_exceptions = {exc.point_category: exc.points_needed for exc in user.point_exceptions} categories = PointCategory.query(ancestor=PointCategory.root_key()) for cat in categories: # TODO (phillip): Write tests to test the behavior when calculating requirement for # a category with children having a higher requirement. (i.e. max(self, children)) # TODO (phillip): remove some of the ugly repeated code below # Add each category and the required number of points if user.is_baby(): requirement = cat.baby_requirement if requirement is None: requirement = 0 sub_req_list = [] for sub in cat.sub_categories: req = sub.get().member_requirement if req is None: sub_req_list.append(0) else: sub_req_list.append(req) sub_req = sum(sub_req_list) requirement = max(requirement, sub_req) else: requirement = cat.member_requirement if requirement is None: requirement = 0 # TODO (phillip): add test when one of the requirements is None sub_req_list = [] for sub in cat.sub_categories: req = sub.get().member_requirement if req is None: sub_req_list.append(0) else: sub_req_list.append(req) sub_req = sum(sub_req_list) requirement = max(requirement, sub_req) if cat.name in point_exceptions: requirement = point_exceptions[cat.name] output["categories"][cat.name] = {u"required": requirement} output["categories"][cat.name]["received"] = 0 if cat.parent is not None: output["categories"][cat.name]["level"] = 2 else: output["categories"][cat.name]["level"] = 1 # NOTE: At this point I am assuming each category has been added to # the output. If this is not true, the following code will fail # miserably. records = PointRecord.query() # username = user.username records = records.filter(PointRecord.username == user.username) for record in records: event = Event.get_from_name(record.event_name) if event is None: logging.error("Uknown event " + record.event_name + " requested for point record: " + str(record)) record.key.delete() continue category = event.point_category.get() if record.points_earned is None: record.points_earned = 0 record.put() output["categories"][category.name]["received"] += record.points_earned # Make sure to also count the points for the parent category if category.parent is not None: output["categories"][category.parent.name]["received"] += record.points_earned output["categories"][category.name]["level"] = 2 output = self.reshape_categories(output) return jsonify(**output)