def get(self): point_categories = PointCategory.query(ancestor=PointCategory.root_key()) out = {} for p in point_categories: if p.parent is None: out[p.name] = { "name": p.name, "baby_requirement": p.baby_requirement, "member_requirement": p.member_requirement, "sub_categories": [], } invalid_keys = [] for key in p.sub_categories: sub = key.get() # The key in sub_categories is no longer valid if sub is None: invalid_keys.append(key) else: sub_cat = { "name": sub.name, "baby_requirement": sub.baby_requirement, "member_requirement": sub.member_requirement, } out[p.name]['sub_categories'].append(sub_cat) for key in invalid_keys: p.sub_categories.remove(key) if invalid_keys: p.put() return jsonify(**out)
def get(self): """ Gets all events that have been created. URL Args: category (str): The category you want the events for. If category is 'all', then this will return all events. Any sub_categories will also be queried for events. """ category = request.args.get("category", "all") if category == 'all': events = Event.query(ancestor=Event.root_key()) else: category = PointCategory.get_from_name(category) if category is None: response = jsonify(message="Category does not exist") response.status_code = 404 return response keys = [] keys.append(category.key) keys.extend(category.sub_categories) events = Event.query(Event.point_category.IN(keys), ancestor=Event.root_key()) events = events.order(Event.date) out = {'events': []} for event in events: out['events'].append({ "name": event.name, "date": event.date.strftime('%m/%d/%Y'), "point-category": event.point_category.get().name, }) return jsonify(**out)
def post(self): """ Creates a new event. """ data = request.form # Don't allow duplicate events event = Event.get_from_name(data['name']) if event is not None: response = jsonify(message="Duplicate resource") response.status_code = 409 return response # Get the point category by name point_category = PointCategory.get_from_name(data['point-category']) if point_category is None: raise Exception("Unknonwn point category: " + data['point-category']) new_event = Event(parent=Event.root_key()) new_event.date = datetime.strptime(data['date'], "%Y-%m-%d") new_event.name = data['name'] new_event.point_category = point_category.key new_event.put() # Make sure there are point records for this event new_event.populate_records() response = jsonify() response.status_code = 201 response.headers['location'] = "/api/events/" + new_event.name.replace(" ", "") return response
def delete(self, name): category = PointCategory.get_from_name(name) if category is None: response = jsonify(message="Resource does not exist") response.status_code = 404 return response category.key.delete();
def reshape_categories(cat_info): """ Reshape flat list of catory information to include structure. Args: cat_info (dict): A flat dictionary of all categories, their point requirements, and their points earned. Returns: A structured dictionary with each category, its sub-categoires, points required, and points earned. """ out = {} # TODO (phillip): this code is probably duplicated from the PointCategoryListAPI point_categories = PointCategory.query(ancestor=PointCategory.root_key()) for cat in point_categories: if cat.parent is None: out[cat.name] = { "required": cat_info["categories"][cat.name]["required"], "received": cat_info["categories"][cat.name]["received"], "level": 1, "sub_categories": {}, } invalid_keys = [] for key in cat.sub_categories: sub = key.get() # The key in sub_categories is no longer valid if sub is None: invalid_keys.append(key) else: sub_cat = { "required": cat_info["categories"][sub.name]["required"], "received": cat_info["categories"][sub.name]["received"], "level": 2, } out[cat.name]["sub_categories"][sub.name] = sub_cat for key in invalid_keys: cat.sub_categories.remove(key) if invalid_keys: cat.put() return out
def get(self, name): category = PointCategory.get_from_name(name) if category is None: response = jsonify(message="Resource does not exist") response.status_code = 404 return response sub_categories = [] for cat in category.sub_categories: sub_categories.append(cat.get().name) data = { "sub_categories": sub_categories, "name": category.name, } return jsonify(**data)
def patch(self, name): data = request.form baby_requirement = data.get('baby_requirement', None) member_requirement = data.get('member_requirement', None) category = PointCategory.get_from_name(name) if baby_requirement is not None: category.baby_requirement = int(baby_requirement) if member_requirement is not None: category.member_requirement = int(member_requirement) category.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 post(self): """ Creates a new point category or updates a duplicate one If this function is given a point category with the same name as one that already exists, it will update the existing point category. It handles removing and adding necessary keys of parent categories. """ data = request.form new_category = None new_key = None # TODO (phillip): we shouldn't put anything in the datastore if there is an error. # Therefore, we should wait until the end of the function to call a # put if possible. # Check to see if the category already exists for category in PointCategory.query(): if category.name == data['name']: new_category = category new_key = new_category.key parent = new_category.parent if parent is not None: # Update old parent sub categories parent.sub_categories.remove(new_key) parent.put() # If the category doesn't exist, create a new one if not new_category: new_category = PointCategory(parent=PointCategory.root_key()) new_category.name = data['name'] new_key = new_category.put() # If necessary, add the proper key to the parent category parent = data.get('parent', None) # TODO (phillip): Should I really also be checking for "none"? Is there a # better way? if parent is not None and parent != "none": parent = PointCategory.get_from_name(parent) parent.sub_categories.append(new_key) parent.put() response = jsonify() response.status_code = 201 response.headers['location'] = "/api/point-categories/" + new_category.name.replace(" ", "") return response
def put(self, event): data = request.form new_event_name = data['name'] dup_event = Event.get_from_name(new_event_name) # Don't allow duplicate events if dup_event is not None and new_event_name.replace(" ", "") != event.replace(" ", ""): response = jsonify(message="Duplicate resource") response.status_code = 409 return response event = Event.get_from_name(event) if event is None: # TODO (phillip): this code is duplicated, maybe make some sort of default # handler that can be called for any resource that doesn't exist? response = jsonify(message="Resource does not exist") response.status_code = 404 return response # Get the point category by name point_category = PointCategory.get_from_name(data['point-category']) if point_category is None: raise Exception("Unknonwn point category: " + data['point-category']) records = PointRecord.query(PointRecord.event_name == event.name) for record in records: record.event_name = data['name'] record.put() event.name = data['name'] event.date = datetime.strptime(data['date'], "%Y-%m-%d") event.point_category = point_category.key event.put() response = jsonify() response.status_code = 201 response.headers['location'] = "/api/events/" + event.name.replace(" ", "") 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)