{"action":"created","comment":{"url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/comments/141612650","pull_request_review_id":65852937,"id":141612650,"diff_hunk":"@@ -0,0 +1,223 @@\n+from abc import ABCMeta, abstractmethod\n+import csv\n+import enum\n+from flask import abort, request, Response\n+from flask.views import View\n+from io import BytesIO\n+from odf.style import TextProperties, TableRowProperties, TableColumnProperties, TableCellProperties, FontFace\n+import six\n+\n+from dmutils import csv_generator\n+from dmutils import ods\n+\n+\n+@six.add_metaclass(ABCMeta)\n+class DownloadFileView(View):\n+    \"\"\"An abstract base class appropriate for subclassing in the frontend apps when the user needs to be able to\n+    download some data as a CSV or ODS file. All abstract methods must be implemented on the subclass; all other\n+    methods should be able to remain as-is to support handling and dispatching the request.\"\"\"\n+\n+    FILETYPES = enum.Enum('Filetypes', ['CSV', 'ODS'])\n+\n+    def __init__(self, **kwargs):\n+        self.request = request\n+\n+        self.data_api_client = None\n+        self.search_api_client = None\n+        self.content_loader = None\n+\n+        super(View, self).__init__(**kwargs)\n+\n+    @abstractmethod\n+    def _init_hook(self, **kwargs):\n+        \"\"\"Hook into the start of the request to associate required clients/loaders with the instance and perform any\n+        other logic required for the start of the request.\"\"\"\n+        self.data_api_client = None\n+        self.search_api_client = None\n+        self.content_loader = None\n+\n+    def _post_request_hook(self, response=None, file_context=None, **kwargs):\n+        \"\"\"A hook that can be used to implement any logic that should be run after the main download file process,\n+        and immediately before sending the response to the user.\"\"\"\n+        pass\n+\n+    @abstractmethod\n+    def get_file_context(self, **kwargs):","path":"dmutils/views.py","position":45,"original_position":45,"commit_id":"02ec39f489a3e936a15c75cd26033a82739e5515","original_commit_id":"02ec39f489a3e936a15c75cd26033a82739e5515","user":{"login":"risicle","id":807447,"avatar_url":"https://avatars3.githubusercontent.com/u/807447?v=4","gravatar_id":"","url":"https://api.github.com/users/risicle","html_url":"https://github.com/risicle","followers_url":"https://api.github.com/users/risicle/followers","following_url":"https://api.github.com/users/risicle/following{/other_user}","gists_url":"https://api.github.com/users/risicle/gists{/gist_id}","starred_url":"https://api.github.com/users/risicle/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/risicle/subscriptions","organizations_url":"https://api.github.com/users/risicle/orgs","repos_url":"https://api.github.com/users/risicle/repos","events_url":"https://api.github.com/users/risicle/events{/privacy}","received_events_url":"https://api.github.com/users/risicle/received_events","type":"User","site_admin":false},"body":"I can see you were using the term \"context\" as used in template rendering, but this confused me - I thought you might be passing around a file context manager.","created_at":"2017-09-28T13:12:37Z","updated_at":"2017-09-28T13:12:38Z","html_url":"https://github.com/alphagov/digitalmarketplace-utils/pull/332#discussion_r141612650","pull_request_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/comments/141612650"},"html":{"href":"https://github.com/alphagov/digitalmarketplace-utils/pull/332#discussion_r141612650"},"pull_request":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332"}}},"pull_request":{"url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332","id":141282759,"html_url":"https://github.com/alphagov/digitalmarketplace-utils/pull/332","diff_url":"https://github.com/alphagov/digitalmarketplace-utils/pull/332.diff","patch_url":"https://github.com/alphagov/digitalmarketplace-utils/pull/332.patch","issue_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/332","number":332,"state":"open","locked":false,"title":"Move ODS module from briefs-frontend and add general DownloadFileView","user":{"login":"samuelhwilliams","id":2920760,"avatar_url":"https://avatars1.githubusercontent.com/u/2920760?v=4","gravatar_id":"","url":"https://api.github.com/users/samuelhwilliams","html_url":"https://github.com/samuelhwilliams","followers_url":"https://api.github.com/users/samuelhwilliams/followers","following_url":"https://api.github.com/users/samuelhwilliams/following{/other_user}","gists_url":"https://api.github.com/users/samuelhwilliams/gists{/gist_id}","starred_url":"https://api.github.com/users/samuelhwilliams/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samuelhwilliams/subscriptions","organizations_url":"https://api.github.com/users/samuelhwilliams/orgs","repos_url":"https://api.github.com/users/samuelhwilliams/repos","events_url":"https://api.github.com/users/samuelhwilliams/events{/privacy}","received_events_url":"https://api.github.com/users/samuelhwilliams/received_events","type":"User","site_admin":false},"body":"## Summary\r\nThe briefs-frontend has a module to help construct ODS files. We now need to make ODSs in the buyer-frontend for service shortlist downloads, so let's move it to utils.\r\n\r\nI've also added a generic `DownloadFileView` that is subclassed in the buyer-frontend (and should be reasonably compatible with the briefs-frontend download view, which I will put up in a separate PR later). This draws out the duplication from the view and lets the subclass only implement the logic and structure required for the csv/ods files, while the parent handles receiving the request and returning the response. Hooks are included for the start and end of the request to allow further logic to be executed at these stages (the shortlist download needs to record the action if the response succeeds).\r\n\r\nBumps version to 28.6.0.\r\n\r\n## Blocked by\r\n* [x] Need to write tests for the DownloadFileView.\r\n\r\n## Required by\r\nhttps://github.com/alphagov/digitalmarketplace-buyer-frontend/pull/615\r\nhttps://github.com/alphagov/digitalmarketplace-briefs-frontend/pull/32\r\n\r\n## Other associated PRs\r\nhttps://github.com/alphagov/digitalmarketplace-api/pull/656\r\n~~https://github.com/alphagov/digitalmarketplace-apiclient/pull/98~~\r\n~~https://github.com/alphagov/digitalmarketplace-frameworks/pull/473~~\r\n\r\n## Ticket\r\nhttps://trello.com/c/igRhA3Bt/711-shortlist-file-download","created_at":"2017-09-15T10:50:25Z","updated_at":"2017-09-28T13:12:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c0b2c988774ed8283456b38e1a3945a72375f96b","assignee":null,"assignees":[],"requested_reviewers":[{"login":"idavidmcdonald","id":7228605,"avatar_url":"https://avatars0.githubusercontent.com/u/7228605?v=4","gravatar_id":"","url":"https://api.github.com/users/idavidmcdonald","html_url":"https://github.com/idavidmcdonald","followers_url":"https://api.github.com/users/idavidmcdonald/followers","following_url":"https://api.github.com/users/idavidmcdonald/following{/other_user}","gists_url":"https://api.github.com/users/idavidmcdonald/gists{/gist_id}","starred_url":"https://api.github.com/users/idavidmcdonald/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/idavidmcdonald/subscriptions","organizations_url":"https://api.github.com/users/idavidmcdonald/orgs","repos_url":"https://api.github.com/users/idavidmcdonald/repos","events_url":"https://api.github.com/users/idavidmcdonald/events{/privacy}","received_events_url":"https://api.github.com/users/idavidmcdonald/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332/commits","review_comments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332/comments","review_comment_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/comments{/number}","comments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/332/comments","statuses_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/statuses/02ec39f489a3e936a15c75cd26033a82739e5515","head":{"label":"alphagov:shw-ods-from-briefs","ref":"shw-ods-from-briefs","sha":"02ec39f489a3e936a15c75cd26033a82739e5515","user":{"login":"alphagov","id":596977,"avatar_url":"https://avatars0.githubusercontent.com/u/596977?v=4","gravatar_id":"","url":"https://api.github.com/users/alphagov","html_url":"https://github.com/alphagov","followers_url":"https://api.github.com/users/alphagov/followers","following_url":"https://api.github.com/users/alphagov/following{/other_user}","gists_url":"https://api.github.com/users/alphagov/gists{/gist_id}","starred_url":"https://api.github.com/users/alphagov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alphagov/subscriptions","organizations_url":"https://api.github.com/users/alphagov/orgs","repos_url":"https://api.github.com/users/alphagov/repos","events_url":"https://api.github.com/users/alphagov/events{/privacy}","received_events_url":"https://api.github.com/users/alphagov/received_events","type":"Organization","site_admin":false},"repo":{"id":34396268,"name":"digitalmarketplace-utils","full_name":"alphagov/digitalmarketplace-utils","owner":{"login":"alphagov","id":596977,"avatar_url":"https://avatars0.githubusercontent.com/u/596977?v=4","gravatar_id":"","url":"https://api.github.com/users/alphagov","html_url":"https://github.com/alphagov","followers_url":"https://api.github.com/users/alphagov/followers","following_url":"https://api.github.com/users/alphagov/following{/other_user}","gists_url":"https://api.github.com/users/alphagov/gists{/gist_id}","starred_url":"https://api.github.com/users/alphagov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alphagov/subscriptions","organizations_url":"https://api.github.com/users/alphagov/orgs","repos_url":"https://api.github.com/users/alphagov/repos","events_url":"https://api.github.com/users/alphagov/events{/privacy}","received_events_url":"https://api.github.com/users/alphagov/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/alphagov/digitalmarketplace-utils","description":"Common utils for Digital Marketplace apps.","fork":false,"url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils","forks_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/forks","keys_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/keys{/key_id}","collaborators_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/teams","hooks_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/hooks","issue_events_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/events{/number}","events_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/events","assignees_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/assignees{/user}","branches_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/branches{/branch}","tags_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/tags","blobs_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/refs{/sha}","trees_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/trees{/sha}","statuses_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/statuses/{sha}","languages_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/languages","stargazers_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/stargazers","contributors_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/contributors","subscribers_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/subscribers","subscription_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/subscription","commits_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/commits{/sha}","git_commits_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/commits{/sha}","comments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/comments{/number}","issue_comment_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/comments{/number}","contents_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/contents/{+path}","compare_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/compare/{base}...{head}","merges_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/merges","archive_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/downloads","issues_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues{/number}","pulls_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls{/number}","milestones_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/milestones{/number}","notifications_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/labels{/name}","releases_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/releases{/id}","deployments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/deployments","created_at":"2015-04-22T14:47:45Z","updated_at":"2016-11-16T10:02:54Z","pushed_at":"2017-09-27T14:52:51Z","git_url":"git://github.com/alphagov/digitalmarketplace-utils.git","ssh_url":"git@github.com:alphagov/digitalmarketplace-utils.git","clone_url":"https://github.com/alphagov/digitalmarketplace-utils.git","svn_url":"https://github.com/alphagov/digitalmarketplace-utils","homepage":null,"size":828,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":2,"forks":8,"open_issues":2,"watchers":2,"default_branch":"master"}},"base":{"label":"alphagov:master","ref":"master","sha":"4d237e2950f2c62ec578702eab597cbe6fd6b079","user":{"login":"alphagov","id":596977,"avatar_url":"https://avatars0.githubusercontent.com/u/596977?v=4","gravatar_id":"","url":"https://api.github.com/users/alphagov","html_url":"https://github.com/alphagov","followers_url":"https://api.github.com/users/alphagov/followers","following_url":"https://api.github.com/users/alphagov/following{/other_user}","gists_url":"https://api.github.com/users/alphagov/gists{/gist_id}","starred_url":"https://api.github.com/users/alphagov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alphagov/subscriptions","organizations_url":"https://api.github.com/users/alphagov/orgs","repos_url":"https://api.github.com/users/alphagov/repos","events_url":"https://api.github.com/users/alphagov/events{/privacy}","received_events_url":"https://api.github.com/users/alphagov/received_events","type":"Organization","site_admin":false},"repo":{"id":34396268,"name":"digitalmarketplace-utils","full_name":"alphagov/digitalmarketplace-utils","owner":{"login":"alphagov","id":596977,"avatar_url":"https://avatars0.githubusercontent.com/u/596977?v=4","gravatar_id":"","url":"https://api.github.com/users/alphagov","html_url":"https://github.com/alphagov","followers_url":"https://api.github.com/users/alphagov/followers","following_url":"https://api.github.com/users/alphagov/following{/other_user}","gists_url":"https://api.github.com/users/alphagov/gists{/gist_id}","starred_url":"https://api.github.com/users/alphagov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alphagov/subscriptions","organizations_url":"https://api.github.com/users/alphagov/orgs","repos_url":"https://api.github.com/users/alphagov/repos","events_url":"https://api.github.com/users/alphagov/events{/privacy}","received_events_url":"https://api.github.com/users/alphagov/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/alphagov/digitalmarketplace-utils","description":"Common utils for Digital Marketplace apps.","fork":false,"url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils","forks_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/forks","keys_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/keys{/key_id}","collaborators_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/teams","hooks_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/hooks","issue_events_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/events{/number}","events_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/events","assignees_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/assignees{/user}","branches_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/branches{/branch}","tags_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/tags","blobs_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/refs{/sha}","trees_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/trees{/sha}","statuses_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/statuses/{sha}","languages_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/languages","stargazers_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/stargazers","contributors_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/contributors","subscribers_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/subscribers","subscription_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/subscription","commits_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/commits{/sha}","git_commits_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/git/commits{/sha}","comments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/comments{/number}","issue_comment_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/comments{/number}","contents_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/contents/{+path}","compare_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/compare/{base}...{head}","merges_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/merges","archive_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/downloads","issues_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues{/number}","pulls_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls{/number}","milestones_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/milestones{/number}","notifications_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/labels{/name}","releases_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/releases{/id}","deployments_url":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/deployments","created_at":"2015-04-22T14:47:45Z","updated_at":"2016-11-16T10:02:54Z","pushed_at":"2017-09-27T14:52:51Z","git_url":"git://github.com/alphagov/digitalmarketplace-utils.git","ssh_url":"git@github.com:alphagov/digitalmarketplace-utils.git","clone_url":"https://github.com/alphagov/digitalmarketplace-utils.git","svn_url":"https://github.com/alphagov/digitalmarketplace-utils","homepage":null,"size":828,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":2,"forks":8,"open_issues":2,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332"},"html":{"href":"https://github.com/alphagov/digitalmarketplace-utils/pull/332"},"issue":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/332"},"comments":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/issues/332/comments"},"review_comments":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332/comments"},"review_comment":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/pulls/332/commits"},"statuses":{"href":"https://api.github.com/repos/alphagov/digitalmarketplace-utils/statuses/02ec39f489a3e936a15c75cd26033a82739e5515"}},"author_association":"NONE"}}
{"actor":{"display_login":"risicle"}}