def create_party(): """ This function gives access to the functionality of creating a new party based on the payload provided in the body. """ try: data = request.get_json() name = data['name'] logoUrl = data['logoUrl'] except: return response_fn( 400, "error", 'Check your json keys. Should be ' 'name and logoUrl') if (not is_valid_string(name)): return response_fn( 400, "error", 'The logoUrl and namefields are ' 'present, but they are not valid') party = PartiesModel(name=name, logoUrl=logoUrl) party.save_party() return response_fn(201, "data", [{ "id": len(PARTIES) - 1, "name": name, "logoUrl": logoUrl }])
def view_activity(user): try: user_id = user[0][1] except: return utils.response_fn(401, "error", "You don't have an account") return utils.response_fn(200, "data", VotesModel.resolve_user_voting_activity(user_id))
def get_all_parties(): """ This method gets all parties """ parties = PartiesModel.get_all_parties() if parties: return utils.response_fn(200, "data", parties) return utils.response_fn(200, "data", [])
def get_specific_party(party_id): """ This method gets a specific party from the db """ party = PartiesModel.get_specific_party(party_id) if party: return utils.response_fn(200, "data", party) return utils.response_fn(404, "error", "Party is not found")
def delete_party(party_id): """ This function provides access to the functionality of deleting a party based on the ID provided. """ party = PartiesModel.deleteparty(party_id) if party: return response_fn(200, "data", "Deleted successfully") return response_fn(404, "data", "This party doesn't exist")
def get_party(party_id): """ This function provides access to the functionality of returning a party whose ID matches the one provided in the url """ party = get_specific_item(PartiesModel, "party", party_id) if party: return response_fn(200, "data", party) return response_fn(404, "error", "This party cannot be found")
def get_specific_office(office_id): """ This method gets a specific office from the list of offices created by the ADMIN. No auth is required here. """ office = OfficesModel.get_specific_office(office_id) if office: return utils.response_fn(200, "data", office) return utils.response_fn(404, "error", "Office is not found")
def user_login(): try: data = request.get_json() email = data['email'] password = data['password'] except KeyError: abort(utils.response_fn(400, "error", "Should be email & password")) # check for the validity of the email v2utils.isEmailValid(email) # check if both values are stirngs utils.check_for_strings(data, ["email", "password"]) # check for whitespaces. utils.check_for_whitespace(data, ["email", "password"]) # try to get the record of the user by email. try: user = UserModel.get_user_by_mail(email) if not user: abort(utils.response_fn(404, "error", "User does not exist")) id = user[0][0] username = user[0][1] hashed_password = user[0][2] is_admin_prop = user[0][4] password = UserModel.check_if_password_n_hash_match( hashed_password, password) if not password: abort( utils.response_fn(400, "error", "The password is wrong, try again")) token = jwt.encode({ "email": email, "isAdmin": is_admin_prop }, KEY, algorithm='HS256') return utils.response_fn( 200, "data", { "message": "Logged in successfully", "token": token.decode('UTF-8'), "user": { "id": id, "username": username } }) except psycopg2.DatabaseError as _error: abort(utils.response_fn(500, "error", "Server error"))
def doPasswordsMatch(pass1, pass2): """ this function checks if the passwords. """ if (pass1 != pass2): abort(response_fn(400, "error", "passwords dont match")) check_password_format(pass1)
def is_phone_number_valid(phone): """ This checks if a number phone number is valid """ if not re.match('^[0-9]*$', phone): abort(response_fn(400, "Error", "Phone number should be integers only"))
def handle_method_not_allowed(*_): """ Handle all 405 errors of method not allowed in the app This occur when a method is used on a route that does not allow the method to be used """ return response_fn(405, "error", "method not allowed")
def authorize_user_to_admin(user, user_id): try: adminprop = user[0][2] except: return utils.response_fn(401, "error", "You don't have an account. Create One") isUserAdmin(adminprop) userToBeElevated = UserModel.get_user_by_id(user_id) if userToBeElevated: UserModel.make_admin(userToBeElevated[0][0]) return utils.response_fn(200, "data", [{ "message": "Admin has been set" }]) return utils.response_fn( 404, "message", "The user you are trying to elevate is not registered")
def register_candidate_to_office(userobj, office_id): """ this is where we check if the candidates information is eligible so that it can be registered to an office. """ try: userAdminProperty = userobj[0][2] except: abort( utils.response_fn(401, "error", "You don't have an account Create one")) try: data = request.get_json() user = data["user"] except KeyError: abort(utils.response_fn(400, "error", "User key should be present")) # check if details are for an admin. isUserAdmin(userAdminProperty) # check if fields are integers. utils.check_for_ints(data, ["user"]) # does the candidate & office exist in the db. candidate = UserModel.get_user_by_id(user) office = OfficesModel.get_specific_office(office_id) if candidate and office: is_candidate_registered = CandidateModel.check_if_candidate_is_already_registered( user, office_id) if is_candidate_registered: abort( utils.response_fn( 400, "error", "Candidate is already registered in this office")) # register the politician user.to a certain office. CandidateModel.register_politician_user_to_office(office_id, user) return utils.response_fn(201, "data", [{ "office": office_id, "user": user }]) else: return utils.response_fn( 404, "error", "Either candidate or office is missing in the database")
def isEmailValid(email): """ this function checks if the email is valid via regex """ if not re.match(r"^[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*$", email): abort(response_fn(400, "error", "email is invalid")) return True
def decorated(*args, **kwargs): token = None if 'x-access-token' in request.headers: token = request.headers['x-access-token'] if not token: return response_fn(401, "error", "Token is missing") try: data = jwt.decode(token, KEY, algorithms='HS256') query = """ SELECT email, id, isAdmin FROM users WHERE users.email = '{}'""".format(data['email']) user = select_data_from_db(query) except: return response_fn(401, "error", "Token is expired or invalid") return f(user, *args, **kwargs)
def reset_password(): try: data = request.get_json() email = data["email"] except KeyError: abort(utils.response_fn(400, "error", "Should be email")) # check if email is valid v2utils.isEmailValid(email) link = "https://tevpolitico.herokuapp.com/api/v2/auth/securereset" # send a request to the endpoint that will send the mail requests.post(link, data=json.dumps({"email": email}), headers={'Content-Type': 'application/json'}) return utils.response_fn(200, "data", [{ "message": "Check your email for password reset link", "email": email }])
def handle_requests(*_): """ This function will be called before all requests will be made. It will check things like the content_type of post requests. Will also check if the json object is syntactically valid """ methods = ["POST", "PATCH"] if (request.method in methods): if (not request.is_json): abort( response_fn(400, "error", "content_type should be application/json")) try: data = request.data json.loads(data) except ValueError: abort(response_fn(400, "error", "Data should be valid json"))
def delete_party(user, party_id): try: """ does the request agent have an account @ politico. """ userAdminProp = user[0][2] except: return utils.response_fn(401, "error", "You don't have an account") # check if the user is an admin user. isUserAdmin(userAdminProp) party = PartiesModel.get_specific_party(party_id) if party: # delete party here PartiesModel.delete_specific_party(party_id) return utils.response_fn(200, "data", [{ "message": "The party with id {} has been deleted".format(party_id) }]) return utils.response_fn(404, "error", "The party does not exist")
def create_office(user): """ This method allows the admin to creates a specific office to the database """ try: userAdminProperty = user[0][2] except: return utils.response_fn( 401, "error", "You don't have an account, Create one first") try: data = request.get_json() name = data['name'] type = data["type"] except KeyError: abort( utils.response_fn(400, "error", "Should be name & type, enter both fields")) try: """ if email matches, admin's then create the party """ # check if details are for an admin. isUserAdmin(userAdminProperty) # check if inputs are all strings utils.check_for_strings(data, ["name", "type"]) # check if fields are blank utils.check_for_whitespace(data, ["name", "type"]) check_matching_items_in_db_table({"name": name}, "offices") newoffice = OfficesModel(name=name, type=type) id = newoffice.save_office() return utils.response_fn(201, "data", [{ "name": name, "id": id, "type": type }]) except psycopg2.DatabaseError as _error: abort(utils.response_fn(500, "error", "Server error"))
def update_party(party_id): """ This function provides access to the update functionality where a party whose id matches the id provided in the url gets updated with the name provided in the payload """ try: data = request.get_json() name = data["name"] except: return response_fn(400, "error", "name not found") if (not is_valid_string(name)): return response_fn(400, "error", "name is present, but its not valid") try: party = PartiesModel.get_party_object(party_id)[0] except IndexError: return response_fn(404, "data", "This party doesn't exist") party.setname(name) return response_fn(200, "data", [{"id": party_id, "name": name}])
def check_password_format(password): ''' Does password meet expectations of passwords that need to be saved ''' # check to confirm the password is of required length if len(password) < 5 or len(password) > 20: abort( response_fn( 400, "error", "Password should not be less than 8 characters or exceed 20")) smallreg = re.search("[a-z]", password) largereg = re.search("[A-Z]", password) numreg = re.search("[0-9]", password) if not smallreg or not largereg or not numreg: abort( response_fn( 400, "error", "Password should contain at least 1 number, 1 small letter and 1 Capital letter" ))
def secure_reset(): """ this endpoint is to be requested from the server only via the /auth/reset view. Client browsers accessing this view will be forbidden and hence the mail will not be sent view https://sendgrid.com/docs/for-developers/sending-email/cors/ for more details on the reasons this implementation is necessary """ try: data = request.get_json() email = data["email"] except KeyError: abort(utils.response_fn(400, "error", "Should be email")) # check if email is valid v2utils.isEmailValid(email) UserModel.sendmail(email) return utils.response_fn(200, "data", [{ "message": "Check your email for password reset link", "email": email }])
def update_password(): try: data = request.get_json() email = data['email'] password = data['password'] except KeyError: abort(utils.response_fn(400, "error", "Should be email & password")) v2utils.check_password_format(password) user = UserModel.get_user_by_mail(email) if not user: abort(utils.response_fn(404, "error", "User does not exist")) UserModel.update_password(email, password) return utils.response_fn( 200, "data", { "message": "Password reset successfully. Login with new password", })
def create_party(user): """ This method allows the admin to creates a specific party to the database """ try: userAdminProp = user[0][2] except: return utils.response_fn(401, "error", "You don't have an account. Create One") try: data = request.get_json() name = data['name'] hqAddress = data["hqAddress"] logoUrl = data.get("logoUrl", "") except KeyError: abort(utils.response_fn(400, "error", "Should be name, hqAddress & logoUrl")) # check for the datatype utils.check_for_strings(data, ["name", "hqAddress", "logoUrl"]) # check for whitespaces. utils.check_for_whitespace(data, ["name", "hqAddress"]) try: """ if email matches, admin's then create the party """ # check if the user is an admin isUserAdmin(userAdminProp) newparty = PartiesModel( name=name, hqAddress=hqAddress, logoUrl=logoUrl) check_matching_items_in_db_table({"name": name}, "parties") id = newparty.save_party() return utils.response_fn(201, "data", [{ "name": name, "id": id }]) except psycopg2.DatabaseError as _error: abort(utils.response_fn(500, "error", "Server error"))
def update_party(user, party_id): """ This method updates a party if it exists """ try: """ is the name attr in the payload of the request? if not throw an error """ data = request.get_json() name = data['name'] except KeyError: abort(utils.response_fn(400, "error", "Provide a name to update")) try: """ is the isAdmin prop is present or empty if its empty then the user does not have an account. """ userAdminProp = user[0][2] except: return utils.response_fn(401, "error", "You don't have an account") # check if the user is an admin isUserAdmin(userAdminProp) # check if data we want to apply strip on is actually a string. utils.check_for_strings(data, ["name"]) # check if data is present ans is not just an empty string.. utils.check_for_whitespace(data, ["name"]) party = PartiesModel.get_specific_party(party_id) if party: # update party here PartiesModel.update_specific_party(name=name, party_id=party_id) return utils.response_fn(200, "data", [{ "name": name, "id": party_id }]) return utils.response_fn(404, "error", "Party is not found")
def check_matching_items_in_db_table(params, table_name): """ check if a value of key provided is available in the database table if there's a duplicate then the test fails """ for key, value in params.items(): query = """ SELECT {} from {} WHERE {}.{} = '{}' """.format(key, table_name, table_name, key, value) duplicated = select_data_from_db(query) if duplicated: abort( response_fn( 409, "error", "Error. '{}' '{}' is already in use".format(key, value)))
def create_vote(user): """ a voter can vote for a particular office if he has hasn't voted for it yet """ try: user_id = user[0][1] except: return utils.response_fn(401, "error", "You don't have an account") try: data = request.get_json() office = data["office"] candidate = data["candidate"] except KeyError: abort(utils.response_fn(400, "error", "Should be office & candidate, enter all fields")) utils.check_for_ints(data, ["office", "candidate"]) try: iscandidatePresent = UserModel.get_user_by_id(candidate) isOfficePresent = OfficesModel.get_specific_office(office) if iscandidatePresent and isOfficePresent: isCandidateRegistered = CandidateModel.check_if_candidate_is_already_registered( candidate, office) if isCandidateRegistered: voted = VotesModel.check_if_user_already_voted(user_id, office) if voted: return utils.response_fn(401, "error", "You have already voted") newvote = VotesModel(office, candidate, user_id) newvote.save_vote() return utils.response_fn(201, "data", [{ "office": office, "candidate": candidate, "voter": user_id }]) return utils.response_fn(400, "error", "This candidate is not registered for the office.") return utils.response_fn(404, "error", "Either Candidate or party doesn't exist") except psycopg2.DatabaseError as _error: abort(utils.response_fn(500, "error", "Server error"))
def handle_all_404(*_): """ Handle all 404 errors in the app. of url not found """ return response_fn(404, "error", "url not found")
def isUserAdmin(adminProp): """ This function checks if the user is an admin. """ if not adminProp: abort(response_fn(401, "error", "You are not an admin"))
def get_all_offices(): """ Get all offices from the database. No authentication is required here. """ return utils.response_fn(200, "data", OfficesModel.get_all_offices())