def get(self, task_id, comment_id): # reconstruct comment key and pull entity from datastore comment_key = ndb.Key(urlsafe=comment_id) comment = comment_key.get() # pull task from datastore task = comment.task.get() if not comment.task.urlsafe() == task_id: return self.abort(400, detail='Task/Comment mismatch') # users can only delete their own comments if not self.user_entity.key == comment.user and not is_admin(self.user_entity): return self.abort(403, detail="Users can only delete their own comments") # delete comment entity comment_key.delete() # re-save task so as to recalculate all computed # fields right the way up to project level task.put() # add flash msg to indicate success self.session.add_flash('Comment successfully deleted') # redirect to task view page redirect_url = self.uri_for('task-view', task_id=task.key.urlsafe()) return self.redirect(redirect_url)
def handle(self): # check if user has admin permissions if not is_admin(self.user_entity): return self.abort(401, detail="Admin permissions required") # populate form with POST data (if available) form = TaskForm(self.request.POST) # check if form was POSTed and that user input validates if self.request.method == 'POST' and form.validate(): # create new project task = Task() # populate task from form form.populate_obj(task) # add user to project's user list and assign to self task.users.append(self.user_entity.key) task.assigned_to = self.user_entity.key # store task in datastore task.put() # record history item history_text = 'Project added' add_to_history(task, self.user_entity, history_text) self.session.add_flash(history_text) # redirect to task view on succesful save redirect_url = self.uri_for('task-view', task_id=task.key.urlsafe()) return self.redirect(redirect_url) # render form and display context = {'form': form, 'task_or_project': 'project', 'add_or_edit': 'Add new'} return self.render_response('task_form.html', context)
def get(self, task_id, user_id): # reconstruct user key from url user_key = ndb.Key(urlsafe=user_id) # pull task from datastore task_key = ndb.Key(urlsafe=task_id) task = task_key.get() if not task.is_top_level: return self.abort(403, detail="Can only remove users from projects") if not user_key in task.users: return self.abort(404, detail='User not assigned to project') # only admin users can modify user lists if not is_admin(self.user_entity): return self.abort(403, detail="Need admin permissions") # delete comment entity task.users.remove(user_key) # re-save task so as to recalculate all computed # fields right the way up to project level task.put() # add flash msg to indicate success self.session.add_flash('User successfully removed from task') # redirect to task view page redirect_url = self.uri_for('task-view', task_id=task.key.urlsafe()) return self.redirect(redirect_url)
def toggle_admin(): if is_admin(): u_id = int(request.args.get('u_id')) db.set_user_admin(u_id, True if db.get_user_admin(u_id) == 0 else False) flash('Administrative privileges toggled.') else: flash('You must be an admin to perform this action.') return redirect(url_for('index')) return redirect(url_for('admin'))
def remove_picture(): if is_admin(): p_id = request.args.get('p_id') db.remove_picture(int(p_id)) flash('Picture removed.') else: flash('You must be an admin to perform this action.') return redirect(url_for('index')) return redirect(url_for('admin'))
def remove_item(): if is_admin(): i_id = request.args.get('i_id') db.remove_item(int(i_id)) flash('Item removed.') else: flash('You must be an admin to perform this action.') return redirect(url_for('index')) return redirect(url_for('admin'))
def admin(): if is_admin(): me = session['u_id'] users = db.get_users() items = db.get_all_items() pictures = db.get_all_pictures() return render_template('admin.html', me = me, users = users, items = items, pictures = pictures) else: flash('You must be an admin to view this page.') return redirect(url_for('index'))
def members(): if is_admin(): member_list = create_members_dictionary(client) length = len(member_list) if member_list is None: flash("Failed to extract member information from Firebase!") return redirect(url_for('error_api.error')) if request.method == "POST": stdid = request.form['reset'] stdname = get_attribute_from_member(client, stdid, 'name') if stdname == -1: flash( "Unable to get member's name. Check log for more details. Source: get_attribute_from_member" ) return redirect(url_for('error_api.error')) change_attribute_of_member(client, stdid, "limit", 5) loaned_items = get_attributes_from_sub_coll(client, stdid, "id") x = delete_sub_coll_x(client, stdid) if x == -1: flash("Unable to delete sub collection from user {}".format( stdid)) return redirect(url_for('error_api.error')) if not loaned_items == -1: for item_id in loaned_items: y = delete_sub_doc(item_id, stdid) if y == -1: flash("Unable to delete {}'s record in item {}".format( stdid, item_id)) return redirect(url_for('error_api.error')) flash( "Member {} {}'s limit has been reset!".format(stdid, stdname), 'success') member_list = create_members_dictionary(client) length = len(member_list) return render_template('members.html', members=member_list, length=length) else: return render_template('members.html', members=member_list, length=length) else: flash("You are unauthorized!") return redirect(url_for('login_api.login'))
def post(self, task_id): # check if user has admin permissions if not is_admin(self.user_entity): return self.abort(401, detail="Admin permissions required") # get task from datastore task_key = ndb.Key(urlsafe=task_id) task = task_key.get() # if this isn't a project then we can't add users to it if not task.is_top_level: return self.abort(403, detail="Cannot add a user to a subtask") # build form with POST data form = add_user_to_task_form(task, self.request.POST) # check if form validates if form.validate() and form.user.data is not None: # coerce form data into valid datastore data data = ndb.Key(urlsafe=form.user.data) # reassign task task.users.append(data) # store task task.put() # record history item history_text = 'Added user:%s to project' % data.get().given_name add_to_history(task, self.user_entity, history_text) self.session.add_flash(history_text) else: # if form doesn't validate then add a flash message before redirecting flash_msg = form.errors self.session.add_flash(flash_msg) # build url of task and redirect to it redirect_url = self.uri_for('task-view', task_id=task.key.urlsafe()) return self.redirect(redirect_url)
def get(self): @ndb.tasklet def get_projects_for_user_async(user_key, admin_permissions): # base projects query projects = Task.query().filter(Task.is_top_level == True) # filter projects if user is not an admin if not admin_permissions: projects = projects.filter(Task.users == user_key) # sort projects by creation date projects = projects.order(Task.creation_time) project_list = yield projects.map_async(lambda x: x.key) raise ndb.Return(project_list) # run async query to get projects admin_permissions = is_admin(self.user_entity) user_key = self.user_entity.key projects = get_projects_for_user_async(user_key, admin_permissions) # add projects to the template context context = {'projects': ndb.get_multi_async(projects.get_result())} # render and return login page return self.render_response('projects.html', context)
def handle(self, task_id): # pull project from datastore or issue 404 task = ndb.Key(urlsafe=task_id).get() if task is None: return self.abort(404, 'Project not found') # check if user has admin permissions if task.is_top_level: if not is_admin(self.user_entity): return self.abort(401, detail="Admin permissions required") task_or_project = 'project' else: task_or_project = 'task' # populate form with POST data (if available) form = TaskForm(self.request.POST, task) # check if form was POSTed and that user input validates if self.request.method == 'POST' and form.validate(): # populate task from form form.populate_obj(task) # store task in datastore task.put() # record history item history_text = '%s edited' % task_or_project.capitalize() add_to_history(task, self.user_entity, history_text) self.session.add_flash(history_text) # redirect to task view on succesful save redirect_url = self.uri_for('task-view', task_id=task.key.urlsafe()) return self.redirect(redirect_url) # render form and display context = {'form': form, 'task_or_project': task_or_project, 'add_or_edit': 'Editing'} return self.render_response('task_form.html', context)
def member_info(student_id): if is_admin(): info = get_loaning_status(client, student_id) name = get_attribute_from_member(client, student_id, 'name') has_expired = False expiry_dates = get_attributes_from_sub_coll(client, student_id, "expiry") now = datetime.datetime.now() for date in expiry_dates: if datetime.datetime.timestamp(now) > datetime.datetime.timestamp( date): has_expired = True break if request.method == "POST": try: remind_btn = request.form['remind'] except: remind_btn = None try: return_one = request.form['return_one'] except: return_one = None try: return_all = request.form['return_all'] except: return_all = None if remind_btn is not None: expired_items_str = "" student_email = get_attribute_from_member( client, student_id, "email") loaned_items = get_loaning_status(client, student_id) now = datetime.datetime.now() for item in loaned_items: expiry = item['expiry'] if datetime.datetime.timestamp( now) > datetime.datetime.timestamp(expiry): expired_items_str += "Item: {} , Item ID: {} , Expiry Date: {}\n".format( item['name'], item['id'], expiry) reminder_email = ''' Dear {}, You have expired item(s) that have yet to be returned! Please return them ASAP otherwise you will not be able to loan any more item. Your expire item is/are: {} Please make an arrangement with any of the exco members via Telegram or Email to return your item. Thank you for your understanding! IEEE SUTD Student Branch IEEE Web Development Team [This is an auto-generated email. Please do not reply.] '''.format(name, expired_items_str) send_email(reminder_email.encode('utf-8'), student_email) flash( "Reminder email has been successfully sent to {}".format( name), 'success') return render_template('member_info.html', info=info, name=name, expired=has_expired) elif return_one is not None: item_id = return_one old_quantity = get_attr_from_sub_doc_x(client, student_id, item_id, "quantity") new_quantity = old_quantity - 1 old_limit = get_attribute_from_member(client, student_id, "limit") if new_quantity == 0: a = delete_sub_doc(item_id, student_id) b = delete_sub_coll_doc(client, student_id, item_id) if a == -1 or b == -1: flash( "Unable to update sub collection loaned item quantity!" ) return redirect(url_for('error_api.error')) else: old_quantity_from_inventory = get_sub_attr_from_member( item_id, student_id, "quantity") new_quantity_from_inventory = old_quantity_from_inventory - 1 status = update_sub_coll_attribute(client, student_id, item_id, "quantity", new_quantity) status_inventory = update_attr_sub_coll( item_id, student_id, "quantity", new_quantity_from_inventory) if status == -1 or status_inventory == -1: flash( "Unable to update sub collection loaned item quantity!" ) return redirect(url_for('error_api.error')) new_limit = old_limit + 1 limit_update = change_attribute_of_member( client, student_id, "limit", new_limit) if limit_update == -1: flash("Failed to update member's limit.") return redirect(url_for('error_api.error')) old_quantity_inventory = get_attribute_value( item_id, "quantity") new_quantity_inventory = old_quantity_inventory + 1 status_update = update_attribute_value(item_id, "quantity", new_quantity_inventory) if status_update == -1: flash( "Failed to update quantity in the main inventory system." ) return redirect(url_for('error_api.error')) info = get_loaning_status(client, student_id) return render_template('member_info.html', info=info, name=name, expired=has_expired) elif return_all is not None: item_id = return_all old_limit = get_attribute_from_member(client, student_id, "limit") old_loaned_quantity = get_attr_from_sub_doc_x( client, student_id, item_id, "quantity") old_quantity_inventory = get_attribute_value( item_id, "quantity") new_quantity_inventory = old_quantity_inventory + old_loaned_quantity new_limit = old_limit + old_loaned_quantity limit_update = change_attribute_of_member( client, student_id, "limit", new_limit) if limit_update == -1: flash("Failed to update member's limit.") return redirect(url_for('error_api.error')) status_update = update_attribute_value(item_id, "quantity", new_quantity_inventory) status_delete = delete_sub_coll_doc(client, student_id, item_id) status_delete_inventory = delete_sub_doc(item_id, student_id) if status_update == -1 or status_delete == -1 or status_delete_inventory == -1: flash( "Failed to update quantity in the main inventory system." ) return redirect(url_for('error_api.error')) info = get_loaning_status(client, student_id) return render_template('member_info.html', info=info, name=name, expired=has_expired) else: return render_template('member_info.html', info=info, name=name, expired=has_expired) else: flash("You are unauthorized!") return redirect(url_for('login_api.login'))
def inventory(): inventory = create_inventory_dictionary() if is_admin(): if request.method == 'POST': try: selection = request.form['inventory-option'] except: selection = None if selection == 'add': try: name = request.form['inventory-name'] except: flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) try: quantity = request.form['inventory-quantity'] if isinstance(quantity, float): flash("Quantity must be an integer!", 'warn') return render_template('inventory.html', inventory=inventory) if quantity == "": flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) except: flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) try: type = request.form['inventory-type'] if type == "": flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) except: flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) try: info = request.form['info'] except: info = "" try: loanable = request.form['inventory-loanable'] loanable = True if loanable == "on" else False except: loanable = False last_id = decode_id(inventory_attr_to_list("id")[-1]) next_id = generate_id(last_id + 1) new_entry = { 'id': next_id, 'name': name, 'type': type, 'quantity': quantity, 'info': info, 'is_allow': loanable } try: create_new_entry(next_id, new_entry) except Exception as e: flash("Failed to create new entry! {}".format(e)) return redirect(url_for('error_api.error')) flash("New entry successfully created. ID: {}".format(next_id), 'success') inventory = create_inventory_dictionary() return render_template('inventory.html', inventory=inventory) elif selection == 'update': try: _id = request.form['update-selection'] if _id == "": flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) except: flash("Please select an item first in order to update! ", 'warn') return render_template('inventory.html', inventory=inventory) try: quantity = request.form['update-quantity'] if isinstance(quantity, float): flash("Quantity must be an integer!", 'warn') return render_template('inventory.html', inventory=inventory) if quantity == "": quantity = "unchanged" except: quantity = "unchanged" try: info = request.form['info2'] if info == "": info = "unchanged" except: info = "unchanged" try: loanable = request.form['update-loanable'] loanable = True if loanable == "on" else False except: loanable = False if info != "unchanged": status = update_attribute_value(_id, 'info', info) if status == -1: return render_template('inventory.html', inventory=inventory) if quantity != 'unchanged': status = update_attribute_value(_id, 'quantity', int(quantity)) if status == -1: return render_template('inventory.html', inventory=inventory) if loanable != 'unchanged': status = update_attribute_value(_id, 'is_allow', loanable) if status == -1: return render_template('inventory.html', inventory=inventory) flash("Item successfully updated. ID: {}".format(_id), 'success') inventory = create_inventory_dictionary() return render_template('inventory.html', inventory=inventory) elif selection == "view": try: _id = request.form['view-inventory'] if _id == "": flash("Fields empty! Unable to add new entry.", 'warn') return render_template('inventory.html', inventory=inventory) except: flash("Please select an item first in order to update! ", 'warn') return render_template('inventory.html', inventory=inventory) return redirect( url_for('admin_api.inventory_info', item_id=_id)) else: flash("Invalid selection!", 'warn') return render_template('inventory.html', inventory=inventory) else: return render_template('inventory.html', inventory=inventory) else: flash("You are unauthorized!") return redirect(url_for('login_api.login'))
def index(): if is_admin(): return render_template('index.html') else: flash("You are unauthorized!") return redirect(url_for('login_api.login'))
def loan(): logged_in = is_login() admin = is_admin() if logged_in: inventory = create_inventory_dictionary() session_name = session['name'] student_id = session['id'] if request.method == "POST": try: picked_id = request.form['select'] except Exception as e: print("No selection is done!", e) flash("You have yet to select anything!") return render_template('loan.html', name=session_name, inventory=inventory, id=student_id, admin=admin) quantity = get_attribute_value(picked_id, "quantity") item_name = get_attribute_value(picked_id, "name") limits = get_attribute_from_member(client, student_id, "limit") expiry_dates = get_attributes_from_sub_coll( client, student_id, "expiry") now = datetime.datetime.now() for date in expiry_dates: if datetime.datetime.timestamp( now) > datetime.datetime.timestamp(date): flash( "You have expired item(s). Please check your loan record and return the expired item before making a new loan!" ) return redirect(url_for('confirm_api.confirm')) if limits == 0: flash( "You have already loaned 5 items! You can't loan until you return them." ) return redirect(url_for('confirm_api.confirm')) if quantity == 0: flash( "You selected an item which is run out. Please select other items we have." ) return redirect(url_for('confirm_api.confirm')) update_attribute_value(picked_id, "quantity", quantity - 1) change_attribute_of_member(client, student_id, "limit", limits - 1) # for inventory side is_exist = check_sub_doc_exist(picked_id, student_id) if is_exist: number = get_sub_attr_from_member(picked_id, student_id, "quantity") if number == -1: number = 0 else: number = 0 # for member side x_is_exist = check_sub_doc_exist_x(client, student_id, picked_id) if x_is_exist: x_number = get_attr_from_sub_doc_x(client, student_id, picked_id, "quantity") if x_number == -1: x_number = 0 else: x_number = 0 expiry = now + datetime.timedelta(days=30) student_email = get_attribute_from_member(client, student_id, "email") std_name = get_attribute_from_member(client, student_id, "name") sub_object = { "student": student_id, "name": std_name, "email": student_email, "quantity": number + 1, "expiry": expiry } sub_object_2 = { "id": picked_id, "name": item_name, "quantity": x_number + 1, "expiry": expiry } inventory_updated = create_sub_collection(picked_id, "loaners", student_id, sub_object) member_updated = create_sub_collection_member( client, student_id, "loaned_items", picked_id, sub_object_2) if inventory_updated == -1 or member_updated == -1: flash("Can't create sub collection!") return redirect(url_for('error_api.error')) new_quantity = get_attribute_value(picked_id, "quantity") new_limit = get_attribute_from_member(client, student_id, "limit") student_name = get_attribute_from_member(client, student_id, "name") student_email = get_attribute_from_member(client, student_id, "email") master_email = ''' [Inventory System Update] --Item: {} --Item ID: {} --Quantity left: {} was loaned out successfully by --Student ID: {} --Studnet name: {} --Remaining loans: {} Item expiry date is set to be: {} '''.format(item_name, picked_id, new_quantity, student_id, student_name, new_limit, datetime.datetime.strftime(now, "%Y-%m-%d %H:%M:%S")) loaner_email = ''' Thank you for using IEEE SUTD Student Branch online inventory loaning system. Here is a summary for your loaning status. --Loaned Item: {} --Item ID: {} --Expiry date: {} Please make an arrangement with any of the exco members via Telegram or Email to collect your item. For further query, please contact us at [email protected] Please remember to return your item before the expiry date. Thank you for your understanding! IEEE SUTD Student Branch IEEE Web Development Team [This is an auto-generated email. Please do not reply.] '''.format(item_name, picked_id, datetime.datetime.strftime(now, "%Y-%m-%d %H:%M:%S")) send_email(master_email.encode('utf-8'), "*****@*****.**") sleep(1) send_email(loaner_email.encode('utf-8'), student_email) flash_message = "You picked {}. " \ "Now left {}. " \ "Remaining number of items you can loan: {}. " \ "Check your loaned item here".format(item_name, new_quantity, new_limit) flash(flash_message) return redirect(url_for('confirm_api.confirm')) else: return render_template('loan.html', name=session_name, inventory=inventory, id=student_id, admin=admin) else: flash("Please login first!") return redirect(url_for('login_api.login'))