diff --git a/Jenkinsfile b/Jenkinsfile index 027bba66fe3b3ae04679d1c4914915bea88e11d9..fdf6368d0ea7bf659e8e819d01fdac1a0a3c5af5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,6 +11,7 @@ pipeline { EB_APP = '' // Value from .global.application_name in EB_CONFIG EB_ENV = '' // "PROJECT-DEPLOY_TO" EB_CONFIG = '.elasticbeanstalk/config.yml' + ECR_REPO_HOST= '763311425122.dkr.ecr.us-east-1.amazonaws.com' NEVER_DEPLOY_ENV = 'none' diff --git a/app/controllers/bgroup.py b/app/controllers/bgroup.py index ec911abd1a13961e5e7fb67e279aa56795608924..1ef19ee2a040aaa7d057f60ab24c92153ab9cfd4 100644 --- a/app/controllers/bgroup.py +++ b/app/controllers/bgroup.py @@ -1,5 +1,5 @@ """Building groups controller""" -from flask import g +from flask import g, current_app from werkzeug.exceptions import BadRequest from .base import RestController from ..forms.bgroup import BGroupForm, BuildingBGroupForm @@ -18,9 +18,11 @@ class BGroupController(RestController): def index(self, filter_data): """Get a query for all models matching filter_data.""" + current_app.logger.info('Checking global permissions') if 'read_all::BGroup' in g.user_permissions: + current_app.logger.info(filter_data) return super().index(filter_data) - + current_app.logger.info('Fetch and check if user has access if not global') user_groups = g.get('user_groups', None) user_group_ids = [group_id for group_id in user_groups] @@ -32,7 +34,7 @@ class BGroupController(RestController): if 'limit' in filter_data: query += 'LIMIT {}'.format(int(filter_data['limit'])) - + current_app.logger.info('execute query') results = self.db.session.execute(query) return [dict(row) for row in results] diff --git a/app/controllers/building.py b/app/controllers/building.py index ed63c05bf48886ca009262a732d38569cbf5c2fc..1d90d2b1ec9b0010efac4a9ce68abff42fca6dd0 100644 --- a/app/controllers/building.py +++ b/app/controllers/building.py @@ -25,9 +25,9 @@ class BuildingController(RestController): dict: List of Buildings """ clean_filter_data = {k: v.strip() for k, v in filter_data.to_dict().items() if v} - + # Call Building list stored procedure try: - building_list = proc(self.Model, self.Model.PROCS['READ'], **clean_filter_data) + building_list = proc(self.Model, self.Model.PROCS['READ_BUILDING'], **clean_filter_data) except Exception as err: raise ( BadRequest(str(err)) if current_app.config['DEBUG'] else @@ -47,27 +47,42 @@ class BuildingController(RestController): dict: Building object """ try: - building_list = proc(self.Model, self.Model.PROCS['READ'], **{'building_id': id_}) + building_list = proc(self.Model, self.Model.PROCS['READ_BUILDING'], **{'building_id': id_}) except Exception as err: raise ( BadRequest(str(err)) if current_app.config['DEBUG'] else BadRequest('Error while executing db call') ) - - if not building_list: - # Hack to try using get by id for Baltimore by using new stored procedure aka postres function - try: - building_list = proc(self.Model, self.Model.PROCS['BALT'], **{'building_id': id_}) - except Exception as err: - raise ( - BadRequest(str(err)) if current_app.config['DEBUG'] else - BadRequest('Error while executing db call') - ) - if not building_list: - raise NotFound address_list = [] for building in building_list: address_list.append(building.street_address) + # Replace the street address of the first record with the address list building_list[0].street_address = address_list + # Return the first record with the address list. + + return building_list[0] + + def post(self, filter_data): + """ + Creates a building object + Args: + filter_data (ImmutableMultiDict): Args for stored proc + Returns: + dict: Building object + """ + clean_filter_data = {k: v.strip() for k, v in filter_data.to_dict().items() if v} + try: + building_list = proc(self.Model, self.Model.PROCS['CREATE_BUILDING'], **clean_filter_data) + except Exception as err: + raise ( + BadRequest(str(err)) if current_app.config['DEBUG'] else + BadRequest('Error while executing db call') + ) + address_list = [] + for building in building_list: + address_list.append(building.street_address) + # Replace the street address of the first record with the address list + building_list[0].street_address = address_list + # Return the first record with the address list. return building_list[0] diff --git a/app/lib/database.py b/app/lib/database.py index 86e3658f5aa0cb239efd29731122ec08ee22b7ec..c1c84241a7f826a6771491421b156b3544c86d84 100644 --- a/app/lib/database.py +++ b/app/lib/database.py @@ -61,6 +61,8 @@ def proc(model, method, limit=None, offset=None, **kwargs): Args: model (class): The class of the db table method (str): Method name for stored procedure + limit: Number of records to return + offset: Offset for the number of records kwargs: Arguments for stored proc Returns: list: Results of the query @@ -76,8 +78,9 @@ def proc(model, method, limit=None, offset=None, **kwargs): input_args[key] = str(value) else: params += "in_{} := null, ".format(key) - params = params[:-2] # remove last comma and space + params = params[:-2] # remove last comma and space from previous loop + # call stored procedure using a select statement query = "select {} from {}.{}({})".format( cols, model.__table_args__['schema'], diff --git a/app/models/base.py b/app/models/base.py index 6def76fdb3ab2df6911c6ec04297fa1787c1e876..a4a5e87a9e8358736b26d61788180c14e91fb5a6 100644 --- a/app/models/base.py +++ b/app/models/base.py @@ -65,11 +65,13 @@ class Model(BaseModel): class User: + """A mixing to include user created and modified.""" user_created = db.Column(db.String(64)) user_modified = db.Column(db.String(64)) class UserGroup: + """A mixing to include UserGroup permissions.""" user_group = db.Column(db.String(36)) diff --git a/app/models/building.py b/app/models/building.py index 1a72e366c065a14230fe513d4b3b60367fdf8e60..8bb3e21246a33528738a2d80af2d806df45acb9d 100644 --- a/app/models/building.py +++ b/app/models/building.py @@ -4,11 +4,14 @@ from .base import BaseModel class Building(BaseModel): + """Model for building using stored procedures. TODO: Change this architecture to use SQLALchemy model""" __table_args__ = {"schema": "public"} + # Stored procedures that return ProcTable below PROCS = { - 'READ': 'building_search', - 'BALT': 'baltimore_building_get', + 'CREATE_BUILDING': 'create_building', + 'READ_BUILDING': 'read_building', + # 'UPDATE_BUILDING': 'update_building' } __table__ = ProcTable( @@ -21,9 +24,10 @@ class Building(BaseModel): ProcColumn('lot_id'), ProcColumn('bin'), ProcColumn('targeting_score'), + ProcColumn('place_name'), ) - def __init__(self, street_address, bbl, borough, zipcode, building_id, lot_id, bin, targeting_score): + def __init__(self, street_address, bbl, borough, zipcode, building_id, lot_id, bin, targeting_score, place_name): self.street_address = street_address self.bbl = bbl self.borough = borough @@ -32,6 +36,7 @@ class Building(BaseModel): self.lot_id = lot_id self.bin = bin self.targeting_score = targeting_score + self.place_name = place_name def __str__(self): - return "Building: {} located at {}".format(self.building_id, self.street_address) + return "Building: {} located at {}".format(self.building_id, self.place_name) diff --git a/app/permissions/authorization.py b/app/permissions/authorization.py index cc939082c2d429a72600d304f86e033ab4d62a55..5268e4781f28e04bf3a7b7c3d3762350c4117af6 100644 --- a/app/permissions/authorization.py +++ b/app/permissions/authorization.py @@ -23,13 +23,13 @@ def secured(f): resource = request.endpoint.split(':').pop(0) if resource.endswith('View'): resource = resource[:-4] - from flask import session auth0_header = current_app.config.get('AUTH0_AUTH_HEADER') headers = {auth0_header: request.headers.get(auth0_header)} params = {'expand': ''} response = services.user.get('/user/{}'.format(g.sub), headers=headers, params=params) + current_app.logger.info('Response status code {}'.format(response.status_code)) if not response.status_code == 200: raise Unauthorized @@ -44,5 +44,7 @@ def secured(f): else: raise Unauthorized + + current_app.logger.info('Authorized request') return f(*args, **kwargs) return decorated_function diff --git a/app/views/bgroup.py b/app/views/bgroup.py index 755b614b14ed56314985c2236922f29ae829c36c..07e784af78bca70f645b045187fc19427f7cd9d0 100644 --- a/app/views/bgroup.py +++ b/app/views/bgroup.py @@ -1,5 +1,5 @@ """Building group view""" -from flask import request +from flask import request, current_app from flask.ext.classy import route from werkzeug.exceptions import MethodNotAllowed from ..views.base import RestView @@ -30,7 +30,11 @@ class BuildingBGroupView(RestView): @route('/', methods=['GET']) def get(self, bgroup_id): """Get buildings within a bgroup""" - return self.json(self.get_controller().get(bgroup_id, request.args)) + current_app.logger.info("in the view") + buildings = self.get_controller().get(bgroup_id, request.args) + current_app.logger.info("controller worked") + current_app.logger.info(buildings) + return self.json(buildings) @route('//', methods=['DELETE']) def delete_building(self, bgroup_id, id_): diff --git a/app/views/building.py b/app/views/building.py index bee088e89ea6d337f466bc4948379a82b9026092..7fcf5b378a873114ab0ddecd9e7628d85c0cfcc6 100644 --- a/app/views/building.py +++ b/app/views/building.py @@ -21,11 +21,12 @@ class BuildingView(UnprotectedRestView): """Parse the model into a dictionary.""" return model.get_dictionary() - # BlocMaps needs to be able to hit this route without a user token + # BIS needs to be able to hit this route without a user token def index(self): """/ GET - Retrieve a list of resources.""" # TODO: Add data key back to self.json # return super(BuildingView, self).index(request.args) + print("entering index") return self.json( [self.parse(m) for m in self.get_controller().index(request.args)] ) @@ -42,10 +43,18 @@ class BuildingView(UnprotectedRestView): ) ) + # BIS needs to be able to hit this route without a user token def post(self): + # TODO: Enable post to create buildings raise MethodNotAllowed() + # return self.json( + # self.parse( + # self.get_controller().post(request.args) + # ) + # ) def put(self, id_): + # TODO: Enable put to update buildings raise MethodNotAllowed() def delete(self, id_): diff --git a/wsgi.py b/wsgi.py index d147c76628e5663775b65db95241715368391318..069f2353c650c90dee7943e97da6d52a84eb15f7 100644 --- a/wsgi.py +++ b/wsgi.py @@ -9,6 +9,6 @@ env = os.environ['ENVIRONMENT'] # Correctly raise a file not found if the specified environment does not exist. app = create_app('config/{}.py'.format(env)) -with app.app_context(): - # Build the database models. - db.create_all() +# with app.app_context(): +# # Build the database models. +# db.create_all()