def create_or_update_program(program_id=None): action = 'update' if program_id else 'create' user = get_user() if not permitted(user, action, 'program', program_id): return "Not authorized", 401 if program_id: program = db_session.query(MonitoringProgram).get(program_id) else: program = MonitoringProgram() if not program: return "Not found", 400 body = request.json errors = validate_fields(program_fields, body) if len(errors): return jsonify(errors), 400 update_program_from_json(program, body) db_session.add(program) db_session.flush() if action == 'create': db_session.execute("""INSERT INTO user_program_manager (user_id, monitoring_program_id) VALUES (:user_id, :program_id)""", { 'program_id': program.id, 'user_id': user.id }) db_session.commit() return jsonify(program_to_json(program)), 200 if program_id else 201
def get_source_processing_notes(source_id=None): user = get_user() if not permitted(user, 'get', 'source', source_id): return "Not authorized", 401 source = db_session.query(Source).get(source_id) if source_id else None if source == None: return "Not found", 404 db_session.execute("SET time_zone = '+00:00'") rows = db_session.execute("""SELECT notes.id, user.first_name, user.last_name, user.email, notes.source_id, notes.time_created, notes.notes, user.id = :user_id AS editable FROM data_processing_notes notes JOIN user ON notes.user_id = user.id WHERE notes.source_id = :source_id """, { 'source_id': source_id, 'user_id': user.id }) return jsonify_rows(rows)
def add_manager_to_monitoring_program(program_id = None): if program_id == None: return "Not found", 404 user = get_user() if not permitted(user, 'mangage_managers', 'program', program_id): return "Not authorized", 401 body = request.json email = body["email"] if not re.match(email_regex, email): return jsonify({ 'error' : '"%s" is not a valid email address' % email }), 400 manager = db_session.query(User).filter(User.email == email).one_or_none() if not manager: manager = User(email=email) db_session.add(manager) db_session.flush() db_session.execute("""REPLACE INTO user_program_manager (user_id, monitoring_program_id) VALUES (:user_id, :program_id)""", { 'user_id': manager.id, 'program_id': program_id }) db_session.commit() return "OK", 201
def get_source_imports(source_id=None): user = get_user() if not permitted(user, 'get', 'source', source_id): return "Not authorized", 401 source = db_session.query(Source).get(source_id) if source_id else None if source == None: return "Not found", 404 db_session.execute("SET time_zone = '+00:00'") rows = db_session.execute("""SELECT data_import.id, data_import.filename, data_import.data_type, data_import_status.code AS status, data_import.time_created, data_import.upload_uuid FROM data_import LEFT JOIN data_import_status ON data_import_status.id = data_import.status_id WHERE data_import.source_id = :source_id """, { 'source_id': source_id }) return jsonify_rows(rows)
def create_user(): body = request.json fields = [ Field(name='email', title='Email address', validators=[validate_required, validate_email]), Field(name='first_name', title='First name', validators=[validate_required, validate_max_chars(255)]), Field(name='last_name', title='Last name', validators=[validate_required, validate_max_chars(255)]), Field(name='phone_number', title='Phone number', validators=[validate_max_chars(32)]), Field(name='password', title='Password', validators=[validate_required, validate_min_chars(8)]) ] errors = validate_fields(fields, body) if len(errors): return jsonify(errors), 400 user = db_session.query(User).filter(User.email == body['email']).one_or_none() if user: if user.password_hash: # User already has an ccount return jsonify({ 'email': "An account with this email address already exists" }), 400 else: user = User(email=body['email'].strip()) user.first_name=body['first_name'].strip() user.last_name=body['last_name'].strip() user.phone_number=body['phone_number'].strip() user.password_hash=pwd_context.hash(body['password']) try: db_session.add(user) db_session.flush() except exc.IntegrityError: # User already exists pass db_session.execute("""INSERT INTO user_role (user_id, role_id) VALUES (:user_id, (SELECT id FROM role WHERE description = 'Custodian'))""", {'user_id': user.id}) db_session.commit() try: email_body = new_account_body.substitute(name=user.first_name) send_email(user.email, 'TSX Account Created', email_body) except Exception as e: print('Error sending email to %s' % user.email) print('Error: %s' % e) return "OK", 204 # Success
def update_user(user_id): body = request.json fields = [ Field(name='email', title='Email address', validators=[validate_required, validate_email]), Field(name='first_name', title='First name', validators=[validate_required, validate_max_chars(255)]), Field(name='last_name', title='Last name', validators=[validate_required, validate_max_chars(255)]), Field(name='phone_number', title='Phone number', validators=[validate_max_chars(32)]) # Field(name='password', title='Password', validators=[validate_required, validate_min_chars(8)]) ] errors = validate_fields(fields, body) if len(errors): return jsonify(errors), 400 user = db_session.query(User).filter(User.id == user_id).one_or_none() if not user: return 'Not found', 404 email = body['email'].strip() email_user = db_session.query(User).filter(User.email == email).one_or_none() if user != email_user: return jsonify({ 'email': 'Email is used by another account' }), 400 user.email = email user.first_name = body['first_name'].strip() user.last_name = body['last_name'].strip() user.phone_number = body['phone_number'].strip() # user.password_hash=pwd_context.hash(body['password']) db_session.commit() return "OK", 204 # Success
def delete_source_processing_notes(source_id=None, note_id=None): user = get_user() if not permitted(user, 'delete', 'source', source_id): return "Not authorized", 401 notes = db_session.query(DataProcessingNotes).get(note_id) if notes.source_id != source_id: return "Source id doesn't match", 400 db_session.delete(notes) db_session.commit() return "OK", 200
def update_source_processing_notes(source_id=None, note_id=None): user = get_user() if not permitted(user, 'update', 'source', source_id): return "Not authorized", 401 notes = db_session.query(DataProcessingNotes).get(note_id) if notes.source_id != source_id: return "Source id doesn't match", 400 body = request.json # TODO: validate json notes.notes = body['notes'] db_session.add(notes) db_session.commit() return "OK", 201
def permitted(user, action, resource_type, resource_id=None): if user == None: return False user_roles = get_roles(user) if 'Administrator' in user_roles: return True if resource_type == 'source': if 'Program manager' in user_roles: if action in ('create', 'list'): return True if action in ('get', 'update', 'download_data') and is_program_manager_of_source( user.id, resource_id): return True if 'Custodian' in user_roles: if action in ('create', 'list'): return True if action in ('get', 'update', 'delete', 'import_data', 'manage_custodians', 'download_data') and is_custodian_of_source( user.id, resource_id): return True if resource_type == 'user': if action in ('list_programs'): return True if resource_type == 'program': if action in ('list_managers'): return True if action in ('download_data', 'update'): return is_program_manager_of_program(user.id, resource_id) if action in ('create'): return 'Program manager' in user_roles if resource_type == 'notes' and 'Custodian' in user_roles: try: notes = db_session.query(DataProcessingNotes).get(resource_id) return notes.user_id == user.id except: return False return False
def get_program(program_id=None): user = get_user() if not permitted(user, 'get', 'program', program_id): return "Not authorized", 401 program = db_session.query(MonitoringProgram).get(program_id) if program_id else None if program == None: return "Not found", 404 result = program_to_json(program) result['can_delete'] = permitted(user, 'delete', 'program', program_id) result['can_manage_managers'] = permitted(user, 'manage_managers', 'program', program_id) return jsonify(result), 200
def get_source(source_id=None): user = get_user() if not permitted(user, 'get', 'source', source_id): return "Not authorized", 401 source = db_session.query(Source).get(source_id) if source_id else None if source == None: return "Not found", 404 result = source_to_json(source) result['can_delete'] = permitted(user, 'delete', 'source', source_id) result['can_import_data'] = permitted(user, 'import_data', 'source', source_id) result['can_manage_custodians'] = permitted(user, 'manage_custodians', 'source', source_id) return jsonify(result), 200
def login(): body = request.json fields = [ Field(name='email', title='Email address', validators=[validate_required, validate_email]), Field(name='password', title='Password', validators=[validate_required]) ] errors = validate_fields(fields, body) if len(errors): return jsonify(errors), 400 user = db_session.query(User).filter(User.email == body['email']).one_or_none() if user is not None and pwd_context.verify(body['password'], user.password_hash): session['user_id'] = user.id return "OK", 200 else: return jsonify({ 'password': "******" }), 400
def get_source_custodians(source_id=None): user = get_user() if not permitted(user, 'manage_custodians', 'source', source_id): return "Not authorized", 401 source = db_session.query(Source).get(source_id) if source_id else None if source == None: return "Not found", 404 rows = db_session.execute("""SELECT user.first_name, user.last_name, user.email, user.id FROM user_source JOIN user ON user_source.user_id = user.id WHERE user_source.source_id = :source_id """, { 'source_id': source_id }) return jsonify_rows(rows)
def create_or_update_source(source_id=None): action = 'update' if source_id else 'create' user = get_user() if not permitted(user, action, 'source', source_id): return "Not authorized", 401 if source_id: source = db_session.query(Source).get(source_id) else: source = Source() if not source: return "Not found", 400 body = request.json errors = validate_fields(source_fields, body) if len(errors): return jsonify(errors), 400 update_source_from_json(source, body) db_session.add(source) db_session.flush() if action == 'create': db_session.execute("""INSERT INTO user_source (user_id, source_id) VALUES (:user_id, :source_id)""", { 'source_id': source.id, 'user_id': user.id }) else: remove_orphaned_monitoring_programs() db_session.commit() return jsonify(source_to_json(source)), 200 if source_id else 201
def create_source_custodian(source_id=None): user = get_user() if not permitted(user, 'manage_custodians', 'source', source_id): return "Not authorized", 401 body = request.json email = body["email"] if not re.match(email_regex, email): return jsonify({ 'error' : '"%s" is not a valid email address' % email }), 400 custodian = db_session.query(User).filter(User.email == email).one_or_none() if not custodian: if auto_create_custodians: custodian = User(email=email) db_session.add(custodian) db_session.flush() else: error_message = 'No user found with the email address "%s". (Note: custodians must first create an account before they can be added)' % email return jsonify({ 'error': error_message }), 400 rows = db_session.execute("""SELECT 1 FROM user_source WHERE user_id = :user_id AND source_id = :source_id """, { 'source_id': source_id, 'user_id': custodian.id }) if len(list(rows)) == 0: db_session.execute("""INSERT INTO user_source (user_id, source_id) VALUES (:user_id, :source_id)""", { 'source_id': source_id, 'user_id': custodian.id }) db_session.commit() return "OK", 201
def reset_password(): body = request.json if 'code' in body: # User already has a code - actually reset the password fields = [ Field(name='password', title='Password', validators=[validate_required, validate_min_chars(8)]) ] errors = validate_fields(fields, body) if len(errors): return jsonify(errors), 400 code = body['code'].strip() user = db_session.query(User).filter(User.password_reset_code == code).one_or_none() if user == None: return jsonify({ 'invalid_code': True }), 400 else: user.password_hash = pwd_context.hash(body['password']) user.password_reset_code = None db_session.commit() return "OK", 200 else: # User doesn't have a code - need to send user a reset link fields = [ Field(name='email', title='Email address', validators=[validate_required, validate_email]) ] errors = validate_fields(fields, body) if len(errors): return jsonify(errors), 400 email = body['email'].strip() user = db_session.query(User).filter(User.email == email).one_or_none() if user.password_hash == None: user = None if user == None: root_url = config.get("api", "root_url") email_body = reset_email_no_account_body.substitute(email=email, root_url=root_url) else: # Update reset code in database user.password_reset_code = secrets.token_urlsafe(16) db_session.commit() # Send reset email root_url = config.get("api", "root_url") reset_url = "%s#/reset_password?code=%s" % (root_url, user.password_reset_code) email_body = reset_email_body.substitute(name=user.first_name, reset_url=reset_url, root_url=root_url) try: send_email(email, 'TSX Password Reset Request', email_body) return "OK", 200 except: return jsonify('There was a problem sending the password reset email. Please try again later.'), 500
def load_import(import_id): try: return db_session.query(DataImport).get(int(import_id)) except: return None