diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index eed9b5c9..6fa7a3b2 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -13,8 +13,7 @@ on: jobs: deploy: - - runs-on: ubuntu-latest + runs-on: ubuntu-latest # nosemgrep : semgrep.dev/s/swati31196:github_provided_runner strategy: max-parallel: 4 matrix: @@ -30,4 +29,4 @@ jobs: pip install responses python3 setup.py install - name: Run Tests - run: python3 -m unittest \ No newline at end of file + run: python3 -m unittest diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..6a035cd4 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,51 @@ +name: SecurityChecks +on: + pull_request: {} + push: + branches: ["master"] + schedule: + - cron: '30 20 * * *' +jobs: + semgrep: + name: Scan + runs-on: [ubuntu-latest] # nosemgrep : semgrep.dev/s/swati31196:github_provided_runner + steps: + - uses: actions/checkout@v2 + - uses: returntocorp/semgrep-action@v1 + with: + publishToken: ${{ secrets.SEMGREP_APP_TOKEN }} + publishDeployment: 339 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + workflow_status: + runs-on: [ ubuntu-latest ] # nosemgrep : semgrep.dev/s/swati31196:github_provided_runner + name: Update Status Check + needs: [ semgrep ] + if: always() + env: + githubCommit: ${{ github.event.pull_request.head.sha }} + steps: + - name: Set github commit id + run: | + if [ "${{ github.event_name }}" = "push" ] || [ "${{ github.event_name }}" = "schedule" ]; then + echo "githubCommit=${{ github.sha }}" >> $GITHUB_ENV + fi + exit 0 + - name: Failed + id: failed + if: (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) && github.ref != 'refs/heads/master' + run: | + echo 'Failing the workflow for github security status check.' + curl -X POST -H "Content-Type: application/json" -H "Authorization: token ${{ github.token }}" \ + -d '{ "state" : "failure" , "context" : "github/security-status-check" , "description" : "github/security-status-check", "target_url" : "https://github.com/${{ github.repository }}" }' \ + https://api.github.com/repos/${{ github.repository }}/statuses/${{ env.githubCommit }} + exit 1 + - name: Success + if: steps.failed.conclusion == 'skipped' || github.ref != 'refs/heads/master' + run: | + echo 'Status check has passed!' + curl -X POST -H "Content-Type: application/json" -H "Authorization: token ${{ github.token }}" \ + -d '{ "state" : "success" , "context" : "github/security-status-check" , "description" : "github/security-status-check", "target_url" : "https://github.com/${{ github.repository }}" }' \ + https://api.github.com/repos/${{ github.repository }}/statuses/${{ env.githubCommit }} + exit 0 diff --git a/razorpay/__init__.py b/razorpay/__init__.py index 1c6a2c1b..c9b9df91 100644 --- a/razorpay/__init__.py +++ b/razorpay/__init__.py @@ -17,6 +17,8 @@ from .resources import Item from .resources import Qrcode from .resources import FundAccount +from .resources import PayoutLink +from .resources import Transaction from .utility import Utility from .constants import ERROR_CODE from .constants import HTTP_STATUS_CODE @@ -39,6 +41,8 @@ 'RegistrationLink', 'Plan', 'FundAccount', + 'PayoutLink', + 'Transaction', 'Settlement', 'Item', 'Qrcode', diff --git a/razorpay/client.py b/razorpay/client.py index ba9ad28b..f835e139 100644 --- a/razorpay/client.py +++ b/razorpay/client.py @@ -83,7 +83,7 @@ def _update_user_agent_header(self, options): def _get_version(self): version = "" - try: + try: # nosemgrep : gitlab.bandit.B110 version = pkg_resources.require("razorpay")[0].version except DistributionNotFound: # pragma: no cover pass @@ -137,7 +137,7 @@ def request(self, method, path, **options): raise BadRequestError(msg) elif str.upper(code) == ERROR_CODE.GATEWAY_ERROR: raise GatewayError(msg) - elif str.upper(code) == ERROR_CODE.SERVER_ERROR: + elif str.upper(code) == ERROR_CODE.SERVER_ERROR: # nosemgrep : python.lang.maintainability.useless-ifelse.useless-if-body raise ServerError(msg) else: raise ServerError(msg) diff --git a/razorpay/constants/url.py b/razorpay/constants/url.py index 3f2be33e..34d7534f 100644 --- a/razorpay/constants/url.py +++ b/razorpay/constants/url.py @@ -17,3 +17,5 @@ class URL(object): QRCODE_URL = "/payments/qr_codes" REGISTRATION_LINK_URL = "/subscription_registration" FUND_ACCOUNT_URL = "/fund_accounts" + PAYOUT_LINKS_URL = "/payout-links" + TRANSACTION_URL = "/transactions" diff --git a/razorpay/resources/__init__.py b/razorpay/resources/__init__.py index 39fa1323..62821d20 100644 --- a/razorpay/resources/__init__.py +++ b/razorpay/resources/__init__.py @@ -16,6 +16,8 @@ from .settlement import Settlement from .item import Item from .fund_account import FundAccount +from .payout_link import PayoutLink +from .transaction import Transaction __all__ = [ 'Payment', @@ -35,5 +37,7 @@ 'Settlement', 'Item', 'QrCode', - 'FundAccount' + 'FundAccount', + 'PayoutLink', + 'Transaction' ] diff --git a/razorpay/resources/payment.py b/razorpay/resources/payment.py index 93a448d2..07195143 100644 --- a/razorpay/resources/payment.py +++ b/razorpay/resources/payment.py @@ -34,7 +34,7 @@ def fetch(self, payment_id, data={}, **kwargs): """ return super(Payment, self).fetch(payment_id, data, **kwargs) - def capture(self, payment_id, amount, data={}, **kwargs): + def capture(self, payment_id, amount, data={}, **kwargs): # nosemgrep : python.lang.correctness.common-mistakes.default-mutable-dict.default-mutable-dict """" Capture Payment for given Id @@ -49,7 +49,7 @@ def capture(self, payment_id, amount, data={}, **kwargs): data['amount'] = amount return self.post_url(url, data, **kwargs) - def refund(self, payment_id, amount, data={}, **kwargs): # pragma: no cover + def refund(self, payment_id, amount, data={}, **kwargs): # pragma: no cover # nosemgrep : python.lang.correctness.common-mistakes.default-mutable-dict.default-mutable-dict """" Refund Payment for given Id diff --git a/razorpay/resources/payout_link.py b/razorpay/resources/payout_link.py new file mode 100644 index 00000000..135791b2 --- /dev/null +++ b/razorpay/resources/payout_link.py @@ -0,0 +1,47 @@ +import warnings + +from .base import Resource +from ..constants import URL + + +class PayoutLink(Resource): + def __init__(self, client=None): + super(PayoutLink, self).__init__(client) + self.base_url = URL.PAYOUT_LINKS_URL + + def create(self, data={}, **kwargs): + """" + Create Payout link from given dict + + Returns: + Payout link Dict which was created + """ + url = self.base_url + return self.post_url(url, data, **kwargs) + + def fetch(self, payoutlink_id, data={}, **kwargs): + """" + Fetch Payout link for given Id + + Args: + payoutlink_id : Id for which payout link object has to be retrieved + + Returns: + Payout link dict + """ + return super(PayoutLink, self).fetch(payoutlink_id, data, **kwargs) + + def fetch_all(self, data={}, **kwargs): # pragma: no cover + warnings.warn("Will be Deprecated in next release, use all", + DeprecationWarning) + return self.all(data, **kwargs) + + def cancel(self, payoutlink_id,data={}, **kwargs): + """ + Cancel a Payout link. + + Returns: + Payout link dict of cancelled Payout link + """ + url = "{}/{}/cancel".format(self.base_url, payoutlink_id) + return self.post_url(url, data, **kwargs) diff --git a/razorpay/resources/transaction.py b/razorpay/resources/transaction.py new file mode 100644 index 00000000..0bc1bc34 --- /dev/null +++ b/razorpay/resources/transaction.py @@ -0,0 +1,27 @@ +import warnings + +from .base import Resource +from ..constants import URL + + +class Transaction(Resource): + def __init__(self, client=None): + super(Transaction, self).__init__(client) + self.base_url = URL.TRANSACTION_URL + + def fetch(self, transaction_id, data={}, **kwargs): + """" + Fetch transaction for given Id + + Args: + transaction_id : Id for which transaction object has to be retrieved + + Returns: + transaction dict + """ + return super(Transaction, self).fetch(transaction_id, data, **kwargs) + + def fetch_all(self, data={}, **kwargs): # pragma: no cover + warnings.warn("Will be Deprecated in next release, use all", + DeprecationWarning) + return self.all(data, **kwargs)