Skip to content

Commit

Permalink
Fixing lint and flake8 errors
Browse files Browse the repository at this point in the history
Fixing lint and flake8 errors

Updating config to reflect new config values

Temporarily removing config required changes
  • Loading branch information
sumesh-aot committed Dec 6, 2019
1 parent 9fc800a commit 519485d
Show file tree
Hide file tree
Showing 25 changed files with 235 additions and 164 deletions.
3 changes: 2 additions & 1 deletion openshift/templates/api-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"NATS_SUBJECT": "entity.filing.payment",
"NATS_QUEUE": "filing-worker",
"BCOL_PAYMENTS_WSDL_URL": "${BCOL_PAYMENTS_WSDL_URL}",
"BCOL_API_ENDPOINT": "https://${BCOL_API_NAME}-${TAG_NAME}.pathfinder.gov.bc.ca/api/v1/reports"
"BCOL_API_ENDPOINT": "https://${BCOL_API_NAME}-${TAG_NAME}.pathfinder.gov.bc.ca/api/v1/reports",
"VALID_REDIRECT_URLS": "https://${AUTH_WEB_NAME}-${TAG_NAME}.pathfinder.gov.bc.ca/cooperatives/*"
}
}
],
Expand Down
7 changes: 6 additions & 1 deletion pay-api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _get_config(config_key: str, **kwargs):
value = os.getenv(config_key, kwargs.get('default'))
else:
value = os.getenv(config_key)
assert value
# assert value TODO Un-comment once we find a solution to run pre-hook without initializing app
return value


Expand Down Expand Up @@ -118,6 +118,9 @@ class _Config(object): # pylint: disable=too-few-public-methods
# BCOL Service
BCOL_API_ENDPOINT = _get_config('BCOL_API_ENDPOINT')

# Valid Payment redirect URLs
VALID_REDIRECT_URLS = [(val.strip() if val != '' else None) for val in _get_config('VALID_REDIRECT_URLS', default='').split(',')]

TESTING = False
DEBUG = True

Expand Down Expand Up @@ -235,6 +238,8 @@ class TestConfig(_Config): # pylint: disable=too-few-public-methods

BCOL_API_ENDPOINT = 'https://mock-lear-tools.pathfinder.gov.bc.ca/rest/bcol-api-1.0.0.yaml/1.0'

VALID_REDIRECT_URLS = ['http://localhost:8080/*']


class ProdConfig(_Config): # pylint: disable=too-few-public-methods
"""Production environment configuration."""
Expand Down
6 changes: 2 additions & 4 deletions pay-api/src/pay_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@

import os

import sentry_sdk
from flask import Flask
from sbc_common_components.exception_handling.exception_handler import ExceptionHandler
from sbc_common_components.utils.camel_case_response import convert_to_camel
from sentry_sdk.integrations.flask import FlaskIntegration # noqa: I001

import sentry_sdk # noqa: I001; pylint: disable=ungrouped-imports; conflicts with Flake8
from sentry_sdk.integrations.flask import FlaskIntegration

import config
from config import _Config
Expand All @@ -33,7 +32,6 @@
from pay_api.utils.run_version import get_run_version


# important to do this first
setup_logging(os.path.join(_Config.PROJECT_ROOT, 'logging.conf'))


Expand Down
4 changes: 2 additions & 2 deletions pay-api/src/pay_api/factory/payment_system_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
from pay_api.exceptions import BusinessException
from pay_api.services.base_payment_system import PaymentSystemService
from pay_api.services.internal_pay_service import InternalPayService
from pay_api.services.bcol_service import BcolService
from pay_api.services.bcol_service import BcolService # noqa: I001
from pay_api.services.paybc_service import PaybcService
from pay_api.utils.enums import Role, PaymentSystem
from pay_api.utils.enums import Role, PaymentSystem # noqa: I001
from pay_api.utils.errors import Error


Expand Down
2 changes: 1 addition & 1 deletion pay-api/src/pay_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .fee_code import FeeCode, FeeCodeSchema
from .fee_schedule import FeeSchedule, FeeScheduleSchema
from .filing_type import FilingType, FilingTypeSchema
from .payment_account import PaymentAccount, PaymentAccountSchema
from .payment_account import PaymentAccount, PaymentAccountSchema # noqa: I001
from .invoice import Invoice, InvoiceSchema
from .invoice_reference import InvoiceReference, InvoiceReferenceSchema
from .payment import Payment, PaymentSchema
Expand Down
10 changes: 3 additions & 7 deletions pay-api/src/pay_api/resources/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"""Resource for Transaction endpoints."""
from http import HTTPStatus

import flask
from flask import current_app, jsonify, request
from flask_restplus import Namespace, Resource, cors

Expand All @@ -36,7 +35,6 @@ class Transaction(Resource):

@staticmethod
@cors.crossdomain(origin='*')
@_jwt.requires_auth
@_tracing.trace()
def post(payment_id):
"""Create the Transaction records."""
Expand All @@ -50,8 +48,7 @@ def post(payment_id):
return jsonify({'code': 'PAY007', 'message': schema_utils.serialize(errors)}), HTTPStatus.BAD_REQUEST

try:
response, status = TransactionService.create(payment_id, request_json,
jwt=_jwt).asdict(), HTTPStatus.CREATED
response, status = TransactionService.create(payment_id, request_json).asdict(), HTTPStatus.CREATED
except BusinessException as exception:
response, status = {'code': exception.code, 'message': exception.message}, exception.status
current_app.logger.debug('>Transaction.post')
Expand Down Expand Up @@ -92,16 +89,15 @@ def get(payment_id, transaction_id):

@staticmethod
@cors.crossdomain(origin='*')
@_jwt.requires_auth
@_tracing.trace()
def patch(payment_id, transaction_id):
"""Update the transaction record by querying payment system."""
current_app.logger.info(
f'<Transaction.post for payment : {payment_id}, and transaction {transaction_id}')
receipt_number = flask.request.args.get('receipt_number')
receipt_number = request.get_json().get('receipt_number', None)
try:
response, status = TransactionService.update_transaction(payment_id, transaction_id,
receipt_number, _jwt).asdict(), HTTPStatus.OK
receipt_number).asdict(), HTTPStatus.OK
except BusinessException as exception:
response, status = {'code': exception.code, 'message': exception.message}, exception.status
current_app.logger.debug('>Transaction.post')
Expand Down
25 changes: 14 additions & 11 deletions pay-api/src/pay_api/services/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,25 @@
from flask_jwt_oidc import JwtManager

from pay_api.services.oauth_service import OAuthService as RestService
from pay_api.utils.enums import AuthHeaderType, ContentType
from pay_api.utils.enums import AuthHeaderType, ContentType, Role


def check_auth(business_identifier: str, jwt: JwtManager, **kwargs):
"""Authorize the user for the business entity."""
bearer_token = jwt.get_token_auth_header() if jwt else None
auth_url = current_app.config.get('AUTH_API_ENDPOINT') + f'entities/{business_identifier}/authorizations'
auth_response = RestService.get(auth_url, bearer_token, AuthHeaderType.BEARER, ContentType.JSON)

is_authorized: bool = False
if auth_response:
roles: list = auth_response.json().get('roles', [])
if kwargs.get('one_of_roles', None):
is_authorized = list(set(kwargs.get('one_of_roles')) & set(roles)) != []
if kwargs.get('contains_role', None):
is_authorized = kwargs.get('contains_role') in roles
if jwt.validate_roles([Role.SYSTEM.value]):
is_authorized = bool(jwt.validate_roles([Role.EDITOR.value]))
else:
bearer_token = jwt.get_token_auth_header() if jwt else None
auth_url = current_app.config.get('AUTH_API_ENDPOINT') + f'entities/{business_identifier}/authorizations'
auth_response = RestService.get(auth_url, bearer_token, AuthHeaderType.BEARER, ContentType.JSON)

if auth_response:
roles: list = auth_response.json().get('roles', [])
if kwargs.get('one_of_roles', None):
is_authorized = list(set(kwargs.get('one_of_roles')) & set(roles)) != []
if kwargs.get('contains_role', None):
is_authorized = kwargs.get('contains_role') in roles

if not is_authorized:
abort(403)
7 changes: 3 additions & 4 deletions pay-api/src/pay_api/services/payment_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,8 @@ def _complete_post_payment(pay_service: PaymentSystemService, payment: Payment):
{
'clientSystemUrl': '',
'payReturnUrl': ''
},
skip_auth_check=True)
transaction.update_transaction(payment.id, transaction.id, receipt_number=None, skip_auth_check=True)
})
transaction.update_transaction(payment.id, transaction.id, receipt_number=None)


def _update_active_transactions(payment_id):
Expand All @@ -375,7 +374,7 @@ def _update_active_transactions(payment_id):
current_app.logger.debug(transaction)
if transaction:
# check existing payment status in PayBC;
PaymentTransaction.update_transaction(payment_id, transaction.id, None, skip_auth_check=True)
PaymentTransaction.update_transaction(payment_id, transaction.id, None)


def _check_if_payment_is_completed(payment):
Expand Down
25 changes: 13 additions & 12 deletions pay-api/src/pay_api/services/payment_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from typing import Dict

from flask import current_app
from flask_jwt_oidc import JwtManager

from pay_api.exceptions import BusinessException, ServiceUnavailableException
from pay_api.factory.payment_system_factory import PaymentSystemFactory
Expand All @@ -29,9 +28,9 @@
from pay_api.services.invoice_reference import InvoiceReference
from pay_api.services.payment_account import PaymentAccount
from pay_api.services.receipt import Receipt
from pay_api.utils.constants import EDIT_ROLE
from pay_api.utils.enums import Status
from pay_api.utils.enums import PaymentSystem, Status
from pay_api.utils.errors import Error
from pay_api.utils.util import is_valid_redirect_url

from .invoice import InvoiceModel
from .payment import Payment
Expand Down Expand Up @@ -182,12 +181,16 @@ def flush(self):
return self._dao.flush()

@staticmethod
def create(payment_identifier: str, request_json: Dict, jwt: JwtManager = None, skip_auth_check: bool = False):
def create(payment_identifier: str, request_json: Dict):
"""Create transaction record."""
current_app.logger.debug('<create transaction')
# Lookup payment record
payment: Payment = Payment.find_by_id(payment_identifier, jwt=jwt, one_of_roles=[EDIT_ROLE],
skip_auth_check=skip_auth_check)
payment: Payment = Payment.find_by_id(payment_identifier, skip_auth_check=True)

# Check if return url is valid
return_url = request_json.get('clientSystemUrl')
if payment.payment_system_code == PaymentSystem.PAYBC.value and not is_valid_redirect_url(return_url):
raise BusinessException(Error.PAY013)

if not payment.id:
raise BusinessException(Error.PAY005)
Expand All @@ -206,7 +209,7 @@ def create(payment_identifier: str, request_json: Dict, jwt: JwtManager = None,

transaction = PaymentTransaction()
transaction.payment_id = payment.id
transaction.client_system_url = request_json.get('clientSystemUrl')
transaction.client_system_url = return_url
transaction.status_code = Status.CREATED.value
transaction_dao = transaction.flush()
transaction._dao = transaction_dao # pylint: disable=protected-access
Expand Down Expand Up @@ -262,8 +265,7 @@ def find_active_by_payment_id(payment_identifier: int):

@staticmethod
def update_transaction(payment_identifier: int, transaction_id: uuid, # pylint: disable=too-many-locals
receipt_number: str, jwt: JwtManager = None,
skip_auth_check: bool = False):
receipt_number: str):
"""Update transaction record.
Does the following:
Expand All @@ -283,8 +285,7 @@ def update_transaction(payment_identifier: int, transaction_id: uuid, # pylint:
if transaction_dao.status_code == Status.COMPLETED.value:
raise BusinessException(Error.PAY006)

payment: Payment = Payment.find_by_id(payment_identifier, jwt=jwt, one_of_roles=[EDIT_ROLE],
skip_auth_check=skip_auth_check)
payment: Payment = Payment.find_by_id(payment_identifier, skip_auth_check=True)

if payment.payment_status_code == Status.COMPLETED.value:
raise BusinessException(Error.PAY010)
Expand All @@ -293,7 +294,7 @@ def update_transaction(payment_identifier: int, transaction_id: uuid, # pylint:
payment_system=payment.payment_system_code
)

invoice = Invoice.find_by_payment_identifier(payment_identifier, jwt=jwt, skip_auth_check=True)
invoice = Invoice.find_by_payment_identifier(payment_identifier, skip_auth_check=True)
invoice_reference = InvoiceReference.find_active_reference_by_invoice_id(invoice.id)
payment_account = PaymentAccount.find_by_id(invoice.account_id)

Expand Down
3 changes: 1 addition & 2 deletions pay-api/src/pay_api/services/queue_publisher.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
import random

from flask import current_app

from nats.aio.client import Client as NATS # noqa N814; by convention the name is NATS
from stan.aio.client import Client as STAN # noqa N814; by convention the name is STAN

from pay_api.utils.handlers import closed_cb, error_cb
from pay_api.utils.handlers import closed_cb, error_cb # noq I001; conflict with flake8


def publish_response(payload):
Expand Down
1 change: 1 addition & 0 deletions pay-api/src/pay_api/utils/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ class Role(Enum):
STAFF = 'staff'
VIEWER = 'view'
EDITOR = 'edit'
SYSTEM = 'system'
2 changes: 2 additions & 0 deletions pay-api/src/pay_api/utils/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class Error(Enum):
PAY010 = 'Payment is already completed', HTTPStatus.BAD_REQUEST
PAY011 = 'Payment is already cancelled', HTTPStatus.BAD_REQUEST
PAY012 = 'Invalid invoice identifier', HTTPStatus.BAD_REQUEST
PAY013 = 'Invalid redirect url', HTTPStatus.UNAUTHORIZED

PAY020 = 'Invalid Account Number for the User', HTTPStatus.BAD_REQUEST
PAY021 = 'Zero dollars deducted from BCOL', HTTPStatus.BAD_REQUEST

Expand Down
12 changes: 12 additions & 0 deletions pay-api/src/pay_api/utils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
A simple decorator to add the options method to a Request Class.
"""
from flask import current_app


def cors_preflight(methods: str = 'GET'):
Expand All @@ -31,3 +32,14 @@ def options(self, *args, **kwargs): # pylint: disable=unused-argument
return f

return wrapper


def is_valid_redirect_url(url: str):
"""Validate if the url is valid based on the VALID Redirect Url."""
valid_urls: list = current_app.config.get('VALID_REDIRECT_URLS')
is_valid = False
for valid_url in valid_urls:
is_valid = url.startswith(valid_url[:-1]) if valid_url.endswith('*') else valid_url == url
if is_valid:
break
return is_valid
28 changes: 25 additions & 3 deletions pay-api/tests/unit/api/test_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

import json
from unittest.mock import patch
from copy import deepcopy

from requests.exceptions import ConnectionError

from pay_api.schemas import utils as schema_utils
from pay_api.utils.enums import Role
from tests.utilities.base_test import (
factory_payment_transaction, get_claims, get_payment_request, get_zero_dollar_payment_request, token_header)

Expand All @@ -41,6 +41,29 @@ def test_payment_creation(session, client, jwt, app):
assert schema_utils.validate(rv.json, 'payment_response')[0]


def test_payment_creation_with_service_account(session, client, jwt, app):
"""Assert that the endpoint returns 201."""
token = jwt.create_jwt(get_claims(roles=[Role.SYSTEM.value, Role.EDITOR.value]), token_header)
headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

rv = client.post(f'/api/v1/payment-requests', data=json.dumps(get_payment_request()),
headers=headers)
assert rv.status_code == 201
assert rv.json.get('_links') is not None

assert schema_utils.validate(rv.json, 'payment_response')[0]


def test_payment_creation_service_account_with_no_edit_role(session, client, jwt, app):
"""Assert that the endpoint returns 403."""
token = jwt.create_jwt(get_claims(role=Role.SYSTEM.value), token_header)
headers = {'Authorization': f'Bearer {token}', 'content-type': 'application/json'}

rv = client.post(f'/api/v1/payment-requests', data=json.dumps(get_payment_request()),
headers=headers)
assert rv.status_code == 403


def test_payment_creation_for_unauthorized_user(session, client, jwt, app):
"""Assert that the endpoint returns 403."""
token = jwt.create_jwt(get_claims(username='TEST', login_source='PASSCODE'), token_header)
Expand Down Expand Up @@ -360,8 +383,7 @@ def test_bcol_payment_creation(session, client, jwt, app):
}

rv = client.post(f'/api/v1/payment-requests', data=json.dumps(payload), headers=headers)
print(rv.json)
assert rv.status_code == 201
assert rv.json.get('_links') is not None

assert schema_utils.validate(rv.json, 'payment_response')[0]
assert schema_utils.validate(rv.json, 'payment_response')[0]
Loading

0 comments on commit 519485d

Please sign in to comment.