def verify_schedule(self, course, person, uid_check=True, exclude_uid=None): for record in person: start = record.course.start_time end = record.course.end_time days = record.course.days if uid_check: # Verify unique assignment or enrollment. if record.course_uid == self.request_data['course_uid']: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.DUPLICATE, 422) # Exclude check against provided course_uid. if exclude_uid != record.course.uid: # Loop through days. for day in course.days: # Check for matching day. if day in days: # Verify that there are no scheduling conflicts. if ((course.start_time > start and course.start_time < end) or (course.end_time > start and course.end_time < end)): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.CONFLICT, 422)
def append_records_list(self, table=None, detail='full', page_length=10, page=None): # Get all records as a query object. query = self.get_all_records() self.response_data.total_records = len(query) # If page is none, returns all records. if page is None: start = 0 stop = None # Checks if page can be converted to a positive integer, and # paginates response. Otherwise, returns a 422 error. else: page = self.string_to_int(page) if page < 1: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_PAGE, 422) start = (page - 1) * page_length stop = start + page_length # Structure details if detail == 'full': self.records = (([record.full() for record in query])[start:stop]) elif detail == 'short': self.records = (([record.short() for record in query])[start:stop]) # Check length of records, error if there are none. if len(self.records) < 1: raise StatusError(STATUS_ERR.CODE_404, STATUS_ERR.NO_RECORDS, 404)
def check_permissions(permission, payload): # Check payload for permissions. if 'permissions' in payload: # Check that required permission is in permissions. if permission not in payload['permissions']: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.NOT_AUTHORIZED, 401) else: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.PERMISSIONS_MISSING, 400) return True
def verify_request_data(self, valid_keys, strict=False): # Verifies that all valid keys are present in the # request body. if strict is True: for data in valid_keys: if data not in self.request_data.keys(): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.MISSING_KEY, 422) # Verifies that there are no invalid keys present # in the request body. for key in self.request_data.keys(): if key not in valid_keys: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_KEY, 422)
def string_to_int(self, int_string): if (type(int_string)) != int: try: int_string = int(int_string) return int_string except ValueError: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_INT, 422)
def get_record_by_id(self, table=None, uid=None): if not table: table = self.table uid = self.uid record = (table.query.filter(table.uid == uid).one_or_none()) if not record: raise StatusError(STATUS_ERR.CODE_404, STATUS_ERR.NO_RECORD, 404) return (record)
def get_course_and_person(self, table, person_uid): course = self.get_record_by_id(table=Course, uid=self.request_data['course_uid']) person = self.get_record_by_id(table=table, uid=self.request_data[person_uid]) if not course or not person: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.INV_ID, 422) return course, person
def verify_phone(self, phone): # Regex validates phone format. if (not re.match(REGEX.PHONE_ONE, phone) and not re.match(REGEX.PHONE_TWO, phone)): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_PHONE, 422) # If phone in 123-456-7890 format, take out dashes. if len(phone) > 10: phone = (phone[:3] + phone[4:7] + phone[8:]) return phone
def verify_days(self): # Verify that provided data is a list. if type(self.request_data['days']) is list: # Loop through list. for day in self.request_data['days']: # Verify day in list is valid, error if not. if (day.casefold() not in map(str.casefold, SCHEDULE.ALLOWED_DAYS)): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_DAY, 422) else: # Check for duplicate values, error if duplicates. if self.request_data['days'].count(day) > 1: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.DUP_DAY, 422) self.request_data['days'] = ','.join(self.request_data['days']) else: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.DAY_LIST, 422)
def verify_time(self, time_list): # If single value passed, convert to list containing single # item. if type(time_list) != list: time_list = [time_list] # Loop list to verify time(s). for time in time_list: if not re.search(r'^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$', time): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_TIME, 422)
def check_unique(self, key, value, uid=None, message=STATUS_ERR.UNIQUE_GENERIC): query = (self.table.query.filter( getattr(self.table, key) == value).first()) # If a record is returned and uid doesn't match # the uid of the record, raise an error. if query is not None and query.uid != uid: raise StatusError(STATUS_ERR.CODE_422, message, 422)
def verify_course_times(self, start_time, end_time): # Convert times to integers. start_time = self.time_to_int(start_time) end_time = self.time_to_int(end_time) # Compare times to validation conditions. duration = end_time - start_time if (duration < 1 or duration < SCHEDULE.MIN_LENGTH or duration > SCHEDULE.MAX_LENGTH or start_time < SCHEDULE.MIN_START or end_time > SCHEDULE.MAX_END): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.INV_TIME, 422)
def get_token_auth_header(): # Gets header. auth_header = request.headers.get("Authorization", None) # Checks for an Authorization header. if not auth_header: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.HEADER_MISSING, 401) # Heater parts to list auth_header_parts = auth_header.split() # Checks that header starts with Bearer. if auth_header_parts[0].lower() != 'bearer': raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.BEARER_MISSING, 401) # Checks for inclusion of token. elif len(auth_header_parts) == 1: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.TOKEN_MISSING, 401) elif len(auth_header_parts) > 2: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.BEARER_TOKEN, 401) # Get token from header and return. return auth_header_parts[1]
def verify_decode_jwt(token): # Get the public key from Auth0.com jsonurl = urlopen('https://' + AUTH0.DOMAIN + '/.well-known/jwks.json') jwks = json.loads(jsonurl.read()) # Get the token from the header. unverified_header = jwt.get_unverified_header(token) rsa_key = {} # Converts public keys to dict. for key in jwks['keys']: if key['kid'] == unverified_header['kid']: rsa_key = { 'kty': key['kty'], 'kid': key['kid'], 'use': key['use'], 'n': key['n'], 'e': key['e'] } # Verify the token if rsa_key: try: payload = jwt.decode(token, rsa_key, algorithms=AUTH0.ALGORITHMS, audience=AUTH0.API_AUDIENCE, issuer='https://' + AUTH0.DOMAIN + '/') except jwt.ExpiredSignatureError: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.TOKEN_EXPIRED, 401) except jwt.JWTClaimsError: raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.INV_CLAIMS, 401) except Exception: raise StatusError(STATUS_ERR.CODE_400, STATUS_ERR.PARSE_TOKEN, 400) _request_ctx_stack.top.current_user = payload return payload raise StatusError(STATUS_ERR.CODE_401, STATUS_ERR.KEY_FIND, 401)
def verify_email(self, email): # Regex validates email format. if not re.search(REGEX.EMAIL, email): raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_EMAIL, 422) # Return email address in lower case. return email.lower()
def time_to_int(self, time_string): try: time_int = (int(time_string[:2]) * 60) + int(time_string[3:]) except ValueError: raise StatusError(STATUS_ERR.CODE_422, STATUS_ERR.BAD_TIME, 422) return time_int
def get_all_records(self): if self.table: return self.table.query.order_by(self.table.uid).all() else: raise StatusError(STATUS_ERR.CODE_500, STATUS_ERR.GENERIC, 500)