{"action":"created","comment":{"url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/comments/214025014","pull_request_review_id":150954638,"id":214025014,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxNDAyNTAxNA==","diff_hunk":"@@ -0,0 +1,102 @@\n+# coding: utf-8\n+\"\"\"\n+Created on 01.06.18\n+@author: Eugeny Kurkovich\n+\"\"\"\n+import os\n+import hmac\n+import json\n+import pytz\n+import hashlib\n+import binascii\n+import datetime\n+\n+import box\n+import requests\n+\n+from urllib.parse import urlencode, urlparse, urlunparse\n+\n+SIGNATURE_VER = \"V1-HMAC-SHA256\"\n+API_DEBUG_VER = \"1\"\n+\n+\n+class ScalrApiSession(requests.Session):\n+\n+    def __init__(self, host, secret_key_id, secret_key, schema=None):\n+        self.base_path = host\n+        self.secret_key_id = secret_key_id\n+        self.secret_key = secret_key\n+        self.schema = schema or \"http\"\n+        super().__init__()\n+\n+    def prepare_request(self, request):\n+        \"\"\"Implements Scalr authentication mechanism\"\"\"\n+\n+        parsed_url = urlparse(request.url)\n+\n+        now = datetime.datetime.now(tz=pytz.timezone(os.environ.get(\"TZ\", \"UTC\")))\n+        sig_date = now.isoformat()\n+\n+        canonical_qs = parsed_url.query\n+        uri = parsed_url.path\n+        method = request.method.upper()\n+\n+        body = request.data or \"\"\n+        string_to_sign = \"\\n\".join((\n+            method,\n+            sig_date,\n+            uri,\n+            canonical_qs,\n+            body))\n+\n+        # Sign request\n+        digest = hmac.new(self.secret_key.encode(), string_to_sign.encode(), hashlib.sha256).digest()\n+        signature = binascii.b2a_base64(digest).strip().decode()\n+\n+        # Update request headers, set auth\n+        headers = dict()\n+        headers['Content-Type'] = 'application/json; charset=utf-8'\n+        headers['X-Scalr-Key-Id'] = self.secret_key_id\n+        headers['X-Scalr-Date'] = sig_date\n+        headers['X-Scalr-Signature'] = '%s %s' % (SIGNATURE_VER, signature)\n+        headers['X-Scalr-Debug'] = API_DEBUG_VER\n+        request.headers.update(headers)\n+\n+        # Prepare request\n+        request = super().prepare_request(request)\n+\n+        return request\n+\n+    def send(self, request, **kwargs):\n+        response = super().send(request, **kwargs)\n+        setattr(response, 'json_data', self.__class__.json_to_box(response))\n+        return response\n+\n+    def request(self, method, endpoint, params, body=None, filters=None,  serializer=None, *args, **kwargs):\n+        # Set uri\n+        uri = endpoint.format(**params)\n+        # Set string to sign\n+        query_string = urlencode(sorted(filters.items())) if filters else \"\"\n+        # Set url\n+        url = urlunparse((self.schema, self.base_path, uri, '', query_string, ''))\n+        body = json.dumps(body, default=serializer) if body else body\n+        resp = super().request(method.lower(), url, data=body, *args, **kwargs)\n+        try:\n+            resp.raise_for_status()\n+        except Exception as e:\n+            errors = [\n+                \"{code}: {msg}\".format(code=e['code'], msg=e['message'])\n+                for e in resp.json().get('errors')\n+            ]\n+            raise e.__class__(\", \".join(errors))\n+        return resp\n+\n+    @staticmethod\n+    def json_to_box(resp):\n+        r = None\n+        if isinstance(resp, requests.models.Response):\n+            try:","path":"api/utils/api_session.py","position":98,"original_position":98,"commit_id":"0ff43413e74a6240fbe2956f554e48b548bc9770","original_commit_id":"0ff43413e74a6240fbe2956f554e48b548bc9770","user":{"login":"gigimon","id":297982,"node_id":"MDQ6VXNlcjI5Nzk4Mg==","avatar_url":"https://avatars2.githubusercontent.com/u/297982?v=4","gravatar_id":"","url":"https://api.github.com/users/gigimon","html_url":"https://github.com/gigimon","followers_url":"https://api.github.com/users/gigimon/followers","following_url":"https://api.github.com/users/gigimon/following{/other_user}","gists_url":"https://api.github.com/users/gigimon/gists{/gist_id}","starred_url":"https://api.github.com/users/gigimon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gigimon/subscriptions","organizations_url":"https://api.github.com/users/gigimon/orgs","repos_url":"https://api.github.com/users/gigimon/repos","events_url":"https://api.github.com/users/gigimon/events{/privacy}","received_events_url":"https://api.github.com/users/gigimon/received_events","type":"User","site_admin":false},"body":"не уверен в верности логики, если мы всегда хотим получать Box объект, то он должен либо вернуться, либо кинуться эксепшен, но никак не None","created_at":"2018-08-30T13:14:30Z","updated_at":"2018-08-30T13:51:27Z","html_url":"https://github.com/Scalr/revizor-tests/pull/185#discussion_r214025014","pull_request_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/comments/214025014"},"html":{"href":"https://github.com/Scalr/revizor-tests/pull/185#discussion_r214025014"},"pull_request":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185"}}},"pull_request":{"url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185","id":193954284,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkzOTU0Mjg0","html_url":"https://github.com/Scalr/revizor-tests/pull/185","diff_url":"https://github.com/Scalr/revizor-tests/pull/185.diff","patch_url":"https://github.com/Scalr/revizor-tests/pull/185.patch","issue_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/185","number":185,"state":"open","locked":false,"title":"REV-407 APIv2 testing framework","user":{"login":"stunko","id":5494706,"node_id":"MDQ6VXNlcjU0OTQ3MDY=","avatar_url":"https://avatars0.githubusercontent.com/u/5494706?v=4","gravatar_id":"","url":"https://api.github.com/users/stunko","html_url":"https://github.com/stunko","followers_url":"https://api.github.com/users/stunko/followers","following_url":"https://api.github.com/users/stunko/following{/other_user}","gists_url":"https://api.github.com/users/stunko/gists{/gist_id}","starred_url":"https://api.github.com/users/stunko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stunko/subscriptions","organizations_url":"https://api.github.com/users/stunko/orgs","repos_url":"https://api.github.com/users/stunko/repos","events_url":"https://api.github.com/users/stunko/events{/privacy}","received_events_url":"https://api.github.com/users/stunko/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-06-11T11:39:41Z","updated_at":"2018-08-30T13:51:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9164e89f208d54380a257214f2b2ccd77bb22ac0","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185/commits","review_comments_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185/comments","review_comment_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/185/comments","statuses_url":"https://api.github.com/repos/Scalr/revizor-tests/statuses/0ff43413e74a6240fbe2956f554e48b548bc9770","head":{"label":"Scalr:feature/REV-407","ref":"feature/REV-407","sha":"0ff43413e74a6240fbe2956f554e48b548bc9770","user":{"login":"Scalr","id":899603,"node_id":"MDEyOk9yZ2FuaXphdGlvbjg5OTYwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/899603?v=4","gravatar_id":"","url":"https://api.github.com/users/Scalr","html_url":"https://github.com/Scalr","followers_url":"https://api.github.com/users/Scalr/followers","following_url":"https://api.github.com/users/Scalr/following{/other_user}","gists_url":"https://api.github.com/users/Scalr/gists{/gist_id}","starred_url":"https://api.github.com/users/Scalr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scalr/subscriptions","organizations_url":"https://api.github.com/users/Scalr/orgs","repos_url":"https://api.github.com/users/Scalr/repos","events_url":"https://api.github.com/users/Scalr/events{/privacy}","received_events_url":"https://api.github.com/users/Scalr/received_events","type":"Organization","site_admin":false},"repo":{"id":8455288,"node_id":"MDEwOlJlcG9zaXRvcnk4NDU1Mjg4","name":"revizor-tests","full_name":"Scalr/revizor-tests","owner":{"login":"Scalr","id":899603,"node_id":"MDEyOk9yZ2FuaXphdGlvbjg5OTYwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/899603?v=4","gravatar_id":"","url":"https://api.github.com/users/Scalr","html_url":"https://github.com/Scalr","followers_url":"https://api.github.com/users/Scalr/followers","following_url":"https://api.github.com/users/Scalr/following{/other_user}","gists_url":"https://api.github.com/users/Scalr/gists{/gist_id}","starred_url":"https://api.github.com/users/Scalr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scalr/subscriptions","organizations_url":"https://api.github.com/users/Scalr/orgs","repos_url":"https://api.github.com/users/Scalr/repos","events_url":"https://api.github.com/users/Scalr/events{/privacy}","received_events_url":"https://api.github.com/users/Scalr/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Scalr/revizor-tests","description":null,"fork":false,"url":"https://api.github.com/repos/Scalr/revizor-tests","forks_url":"https://api.github.com/repos/Scalr/revizor-tests/forks","keys_url":"https://api.github.com/repos/Scalr/revizor-tests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Scalr/revizor-tests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Scalr/revizor-tests/teams","hooks_url":"https://api.github.com/repos/Scalr/revizor-tests/hooks","issue_events_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/events{/number}","events_url":"https://api.github.com/repos/Scalr/revizor-tests/events","assignees_url":"https://api.github.com/repos/Scalr/revizor-tests/assignees{/user}","branches_url":"https://api.github.com/repos/Scalr/revizor-tests/branches{/branch}","tags_url":"https://api.github.com/repos/Scalr/revizor-tests/tags","blobs_url":"https://api.github.com/repos/Scalr/revizor-tests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Scalr/revizor-tests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Scalr/revizor-tests/git/refs{/sha}","trees_url":"https://api.github.com/repos/Scalr/revizor-tests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Scalr/revizor-tests/statuses/{sha}","languages_url":"https://api.github.com/repos/Scalr/revizor-tests/languages","stargazers_url":"https://api.github.com/repos/Scalr/revizor-tests/stargazers","contributors_url":"https://api.github.com/repos/Scalr/revizor-tests/contributors","subscribers_url":"https://api.github.com/repos/Scalr/revizor-tests/subscribers","subscription_url":"https://api.github.com/repos/Scalr/revizor-tests/subscription","commits_url":"https://api.github.com/repos/Scalr/revizor-tests/commits{/sha}","git_commits_url":"https://api.github.com/repos/Scalr/revizor-tests/git/commits{/sha}","comments_url":"https://api.github.com/repos/Scalr/revizor-tests/comments{/number}","issue_comment_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/comments{/number}","contents_url":"https://api.github.com/repos/Scalr/revizor-tests/contents/{+path}","compare_url":"https://api.github.com/repos/Scalr/revizor-tests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Scalr/revizor-tests/merges","archive_url":"https://api.github.com/repos/Scalr/revizor-tests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Scalr/revizor-tests/downloads","issues_url":"https://api.github.com/repos/Scalr/revizor-tests/issues{/number}","pulls_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls{/number}","milestones_url":"https://api.github.com/repos/Scalr/revizor-tests/milestones{/number}","notifications_url":"https://api.github.com/repos/Scalr/revizor-tests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Scalr/revizor-tests/labels{/name}","releases_url":"https://api.github.com/repos/Scalr/revizor-tests/releases{/id}","deployments_url":"https://api.github.com/repos/Scalr/revizor-tests/deployments","created_at":"2013-02-27T12:15:45Z","updated_at":"2018-08-16T10:46:55Z","pushed_at":"2018-08-29T11:30:34Z","git_url":"git://github.com/Scalr/revizor-tests.git","ssh_url":"git@github.com:Scalr/revizor-tests.git","clone_url":"https://github.com/Scalr/revizor-tests.git","svn_url":"https://github.com/Scalr/revizor-tests","homepage":null,"size":2328,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":6,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":3,"open_issues":6,"watchers":0,"default_branch":"master"}},"base":{"label":"Scalr:master","ref":"master","sha":"52ac578a9c52f1fcfbed690b8a13a27c093a1668","user":{"login":"Scalr","id":899603,"node_id":"MDEyOk9yZ2FuaXphdGlvbjg5OTYwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/899603?v=4","gravatar_id":"","url":"https://api.github.com/users/Scalr","html_url":"https://github.com/Scalr","followers_url":"https://api.github.com/users/Scalr/followers","following_url":"https://api.github.com/users/Scalr/following{/other_user}","gists_url":"https://api.github.com/users/Scalr/gists{/gist_id}","starred_url":"https://api.github.com/users/Scalr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scalr/subscriptions","organizations_url":"https://api.github.com/users/Scalr/orgs","repos_url":"https://api.github.com/users/Scalr/repos","events_url":"https://api.github.com/users/Scalr/events{/privacy}","received_events_url":"https://api.github.com/users/Scalr/received_events","type":"Organization","site_admin":false},"repo":{"id":8455288,"node_id":"MDEwOlJlcG9zaXRvcnk4NDU1Mjg4","name":"revizor-tests","full_name":"Scalr/revizor-tests","owner":{"login":"Scalr","id":899603,"node_id":"MDEyOk9yZ2FuaXphdGlvbjg5OTYwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/899603?v=4","gravatar_id":"","url":"https://api.github.com/users/Scalr","html_url":"https://github.com/Scalr","followers_url":"https://api.github.com/users/Scalr/followers","following_url":"https://api.github.com/users/Scalr/following{/other_user}","gists_url":"https://api.github.com/users/Scalr/gists{/gist_id}","starred_url":"https://api.github.com/users/Scalr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scalr/subscriptions","organizations_url":"https://api.github.com/users/Scalr/orgs","repos_url":"https://api.github.com/users/Scalr/repos","events_url":"https://api.github.com/users/Scalr/events{/privacy}","received_events_url":"https://api.github.com/users/Scalr/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Scalr/revizor-tests","description":null,"fork":false,"url":"https://api.github.com/repos/Scalr/revizor-tests","forks_url":"https://api.github.com/repos/Scalr/revizor-tests/forks","keys_url":"https://api.github.com/repos/Scalr/revizor-tests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Scalr/revizor-tests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Scalr/revizor-tests/teams","hooks_url":"https://api.github.com/repos/Scalr/revizor-tests/hooks","issue_events_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/events{/number}","events_url":"https://api.github.com/repos/Scalr/revizor-tests/events","assignees_url":"https://api.github.com/repos/Scalr/revizor-tests/assignees{/user}","branches_url":"https://api.github.com/repos/Scalr/revizor-tests/branches{/branch}","tags_url":"https://api.github.com/repos/Scalr/revizor-tests/tags","blobs_url":"https://api.github.com/repos/Scalr/revizor-tests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Scalr/revizor-tests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Scalr/revizor-tests/git/refs{/sha}","trees_url":"https://api.github.com/repos/Scalr/revizor-tests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Scalr/revizor-tests/statuses/{sha}","languages_url":"https://api.github.com/repos/Scalr/revizor-tests/languages","stargazers_url":"https://api.github.com/repos/Scalr/revizor-tests/stargazers","contributors_url":"https://api.github.com/repos/Scalr/revizor-tests/contributors","subscribers_url":"https://api.github.com/repos/Scalr/revizor-tests/subscribers","subscription_url":"https://api.github.com/repos/Scalr/revizor-tests/subscription","commits_url":"https://api.github.com/repos/Scalr/revizor-tests/commits{/sha}","git_commits_url":"https://api.github.com/repos/Scalr/revizor-tests/git/commits{/sha}","comments_url":"https://api.github.com/repos/Scalr/revizor-tests/comments{/number}","issue_comment_url":"https://api.github.com/repos/Scalr/revizor-tests/issues/comments{/number}","contents_url":"https://api.github.com/repos/Scalr/revizor-tests/contents/{+path}","compare_url":"https://api.github.com/repos/Scalr/revizor-tests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Scalr/revizor-tests/merges","archive_url":"https://api.github.com/repos/Scalr/revizor-tests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Scalr/revizor-tests/downloads","issues_url":"https://api.github.com/repos/Scalr/revizor-tests/issues{/number}","pulls_url":"https://api.github.com/repos/Scalr/revizor-tests/pulls{/number}","milestones_url":"https://api.github.com/repos/Scalr/revizor-tests/milestones{/number}","notifications_url":"https://api.github.com/repos/Scalr/revizor-tests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Scalr/revizor-tests/labels{/name}","releases_url":"https://api.github.com/repos/Scalr/revizor-tests/releases{/id}","deployments_url":"https://api.github.com/repos/Scalr/revizor-tests/deployments","created_at":"2013-02-27T12:15:45Z","updated_at":"2018-08-16T10:46:55Z","pushed_at":"2018-08-29T11:30:34Z","git_url":"git://github.com/Scalr/revizor-tests.git","ssh_url":"git@github.com:Scalr/revizor-tests.git","clone_url":"https://github.com/Scalr/revizor-tests.git","svn_url":"https://github.com/Scalr/revizor-tests","homepage":null,"size":2328,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":6,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":3,"open_issues":6,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185"},"html":{"href":"https://github.com/Scalr/revizor-tests/pull/185"},"issue":{"href":"https://api.github.com/repos/Scalr/revizor-tests/issues/185"},"comments":{"href":"https://api.github.com/repos/Scalr/revizor-tests/issues/185/comments"},"review_comments":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185/comments"},"review_comment":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Scalr/revizor-tests/pulls/185/commits"},"statuses":{"href":"https://api.github.com/repos/Scalr/revizor-tests/statuses/0ff43413e74a6240fbe2956f554e48b548bc9770"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"gigimon"}}