{"action":"created","comment":{"url":"https://api.github.com/repos/google/oauth2client/pulls/comments/71048539","id":71048539,"diff_hunk":"@@ -12,16 +12,78 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n-from oauth2client.contrib.dictionary_storage import DictionaryStorage\n+\"\"\"Contains a storage module that stores credentials using the Django\n+ORM.\"\"\"\n \n-_CREDENTIALS_KEY = 'google_oauth2_credentials'\n+from oauth2client.client import Error, Storage\n \n \n-def get_storage(request):\n-    # TODO(issue 319): Make this pluggable with different storage providers\n-    # https://github.com/google/oauth2client/issues/319\n-    \"\"\" Gets a Credentials storage object for the Django OAuth2 Helper object\n-    :param request: Reference to the current request object\n-    :return: A OAuth2Client Storage implementation based on sessions\n+class DjangoORMError(Error):\n+    \"\"\"Error raised when there is an error interacting with the Django ORM.\"\"\"\n+    pass\n+\n+\n+class DjangoORMStorage(Storage):\n+    \"\"\"Store and retrieve a single credential to and from the Django datastore.\n+\n+    This Storage helper presumes the Credentials\n+    have been stored as a CredentialsField\n+    on a db model class.\n     \"\"\"\n-    return DictionaryStorage(request.session, key=_CREDENTIALS_KEY)\n+\n+    def __init__(self, model_class, key_name, key_value, property_name):\n+        \"\"\"Constructor for Storage.\n+\n+        Args:\n+            model: string, fully qualified name of db.Model, model class\n+            key_name: string, key name for the entity that has the credentials\n+            key_value: string, key value for the entity that has the\n+                       credentials","path":"oauth2client/contrib/django_util/storage.py","position":36,"original_position":39,"commit_id":"08216201de0a4dd5f90ca1aa318dc7bde812bbc6","original_commit_id":"606abcc961449560c2815710e8ece6b264eeadce","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"body":"done","created_at":"2016-07-15T22:19:13Z","updated_at":"2016-07-15T22:19:13Z","html_url":"https://github.com/google/oauth2client/pull/546#discussion_r71048539","pull_request_url":"https://api.github.com/repos/google/oauth2client/pulls/546","_links":{"self":{"href":"https://api.github.com/repos/google/oauth2client/pulls/comments/71048539"},"html":{"href":"https://github.com/google/oauth2client/pull/546#discussion_r71048539"},"pull_request":{"href":"https://api.github.com/repos/google/oauth2client/pulls/546"}}},"pull_request":{"url":"https://api.github.com/repos/google/oauth2client/pulls/546","id":77537263,"html_url":"https://github.com/google/oauth2client/pull/546","diff_url":"https://github.com/google/oauth2client/pull/546.diff","patch_url":"https://github.com/google/oauth2client/pull/546.patch","issue_url":"https://api.github.com/repos/google/oauth2client/issues/546","number":546,"state":"open","locked":false,"title":"Django Refactors","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"body":"Primarily addressed #494 \r\n\r\nMoves all Django code into contrib.django_util.\r\n\r\nAdds new functionality to decorators and views that integrate with ORM\r\nstorage.\r\n\r\nAdds two Django samples for the primary two use cases - using Google\r\nOAuth as the primary auth, and integrating it into exisiting user\r\nsystem.\r\n\r\nDjangORMStorage is backwards compatible with old django_orm storage.\r\n\r\nFixes issue where Django storage was always creating new Models.\r\n\r\nMove tests into Django package and have them create an actual test app\r\nto create test databases etc.\r\n\r\nKills FlowField as its not useful.","created_at":"2016-07-14T22:33:38Z","updated_at":"2016-07-15T22:19:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9c41dd78219d296966bc23185efa5e9c1da2f80a","assignee":{"login":"jonparrott","id":250995,"avatar_url":"https://avatars.githubusercontent.com/u/250995?v=3","gravatar_id":"","url":"https://api.github.com/users/jonparrott","html_url":"https://github.com/jonparrott","followers_url":"https://api.github.com/users/jonparrott/followers","following_url":"https://api.github.com/users/jonparrott/following{/other_user}","gists_url":"https://api.github.com/users/jonparrott/gists{/gist_id}","starred_url":"https://api.github.com/users/jonparrott/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonparrott/subscriptions","organizations_url":"https://api.github.com/users/jonparrott/orgs","repos_url":"https://api.github.com/users/jonparrott/repos","events_url":"https://api.github.com/users/jonparrott/events{/privacy}","received_events_url":"https://api.github.com/users/jonparrott/received_events","type":"User","site_admin":false},"assignees":[{"login":"jonparrott","id":250995,"avatar_url":"https://avatars.githubusercontent.com/u/250995?v=3","gravatar_id":"","url":"https://api.github.com/users/jonparrott","html_url":"https://github.com/jonparrott","followers_url":"https://api.github.com/users/jonparrott/followers","following_url":"https://api.github.com/users/jonparrott/following{/other_user}","gists_url":"https://api.github.com/users/jonparrott/gists{/gist_id}","starred_url":"https://api.github.com/users/jonparrott/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonparrott/subscriptions","organizations_url":"https://api.github.com/users/jonparrott/orgs","repos_url":"https://api.github.com/users/jonparrott/repos","events_url":"https://api.github.com/users/jonparrott/events{/privacy}","received_events_url":"https://api.github.com/users/jonparrott/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/google/oauth2client/pulls/546/commits","review_comments_url":"https://api.github.com/repos/google/oauth2client/pulls/546/comments","review_comment_url":"https://api.github.com/repos/google/oauth2client/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/oauth2client/issues/546/comments","statuses_url":"https://api.github.com/repos/google/oauth2client/statuses/08216201de0a4dd5f90ca1aa318dc7bde812bbc6","head":{"label":"waprin:refactor","ref":"refactor","sha":"08216201de0a4dd5f90ca1aa318dc7bde812bbc6","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"repo":{"id":44128520,"name":"oauth2client","full_name":"waprin/oauth2client","owner":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/waprin/oauth2client","description":"This is a Python library for accessing resources protected by OAuth 2.0.","fork":true,"url":"https://api.github.com/repos/waprin/oauth2client","forks_url":"https://api.github.com/repos/waprin/oauth2client/forks","keys_url":"https://api.github.com/repos/waprin/oauth2client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/waprin/oauth2client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/waprin/oauth2client/teams","hooks_url":"https://api.github.com/repos/waprin/oauth2client/hooks","issue_events_url":"https://api.github.com/repos/waprin/oauth2client/issues/events{/number}","events_url":"https://api.github.com/repos/waprin/oauth2client/events","assignees_url":"https://api.github.com/repos/waprin/oauth2client/assignees{/user}","branches_url":"https://api.github.com/repos/waprin/oauth2client/branches{/branch}","tags_url":"https://api.github.com/repos/waprin/oauth2client/tags","blobs_url":"https://api.github.com/repos/waprin/oauth2client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/waprin/oauth2client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/waprin/oauth2client/git/refs{/sha}","trees_url":"https://api.github.com/repos/waprin/oauth2client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/waprin/oauth2client/statuses/{sha}","languages_url":"https://api.github.com/repos/waprin/oauth2client/languages","stargazers_url":"https://api.github.com/repos/waprin/oauth2client/stargazers","contributors_url":"https://api.github.com/repos/waprin/oauth2client/contributors","subscribers_url":"https://api.github.com/repos/waprin/oauth2client/subscribers","subscription_url":"https://api.github.com/repos/waprin/oauth2client/subscription","commits_url":"https://api.github.com/repos/waprin/oauth2client/commits{/sha}","git_commits_url":"https://api.github.com/repos/waprin/oauth2client/git/commits{/sha}","comments_url":"https://api.github.com/repos/waprin/oauth2client/comments{/number}","issue_comment_url":"https://api.github.com/repos/waprin/oauth2client/issues/comments{/number}","contents_url":"https://api.github.com/repos/waprin/oauth2client/contents/{+path}","compare_url":"https://api.github.com/repos/waprin/oauth2client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/waprin/oauth2client/merges","archive_url":"https://api.github.com/repos/waprin/oauth2client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/waprin/oauth2client/downloads","issues_url":"https://api.github.com/repos/waprin/oauth2client/issues{/number}","pulls_url":"https://api.github.com/repos/waprin/oauth2client/pulls{/number}","milestones_url":"https://api.github.com/repos/waprin/oauth2client/milestones{/number}","notifications_url":"https://api.github.com/repos/waprin/oauth2client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/waprin/oauth2client/labels{/name}","releases_url":"https://api.github.com/repos/waprin/oauth2client/releases{/id}","deployments_url":"https://api.github.com/repos/waprin/oauth2client/deployments","created_at":"2015-10-12T19:12:47Z","updated_at":"2016-04-08T22:23:23Z","pushed_at":"2016-07-15T22:06:38Z","git_url":"git://github.com/waprin/oauth2client.git","ssh_url":"git@github.com:waprin/oauth2client.git","clone_url":"https://github.com/waprin/oauth2client.git","svn_url":"https://github.com/waprin/oauth2client","homepage":"","size":23674,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"google:master","ref":"master","sha":"cd635f4d1e2ce1a70155a52deb0e22ad6da1e6e5","user":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":14211461,"name":"oauth2client","full_name":"google/oauth2client","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/oauth2client","description":"This is a Python library for accessing resources protected by OAuth 2.0.","fork":false,"url":"https://api.github.com/repos/google/oauth2client","forks_url":"https://api.github.com/repos/google/oauth2client/forks","keys_url":"https://api.github.com/repos/google/oauth2client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/oauth2client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/oauth2client/teams","hooks_url":"https://api.github.com/repos/google/oauth2client/hooks","issue_events_url":"https://api.github.com/repos/google/oauth2client/issues/events{/number}","events_url":"https://api.github.com/repos/google/oauth2client/events","assignees_url":"https://api.github.com/repos/google/oauth2client/assignees{/user}","branches_url":"https://api.github.com/repos/google/oauth2client/branches{/branch}","tags_url":"https://api.github.com/repos/google/oauth2client/tags","blobs_url":"https://api.github.com/repos/google/oauth2client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/oauth2client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/oauth2client/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/oauth2client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/oauth2client/statuses/{sha}","languages_url":"https://api.github.com/repos/google/oauth2client/languages","stargazers_url":"https://api.github.com/repos/google/oauth2client/stargazers","contributors_url":"https://api.github.com/repos/google/oauth2client/contributors","subscribers_url":"https://api.github.com/repos/google/oauth2client/subscribers","subscription_url":"https://api.github.com/repos/google/oauth2client/subscription","commits_url":"https://api.github.com/repos/google/oauth2client/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/oauth2client/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/oauth2client/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/oauth2client/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/oauth2client/contents/{+path}","compare_url":"https://api.github.com/repos/google/oauth2client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/oauth2client/merges","archive_url":"https://api.github.com/repos/google/oauth2client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/oauth2client/downloads","issues_url":"https://api.github.com/repos/google/oauth2client/issues{/number}","pulls_url":"https://api.github.com/repos/google/oauth2client/pulls{/number}","milestones_url":"https://api.github.com/repos/google/oauth2client/milestones{/number}","notifications_url":"https://api.github.com/repos/google/oauth2client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/oauth2client/labels{/name}","releases_url":"https://api.github.com/repos/google/oauth2client/releases{/id}","deployments_url":"https://api.github.com/repos/google/oauth2client/deployments","created_at":"2013-11-07T18:03:04Z","updated_at":"2016-07-15T17:51:34Z","pushed_at":"2016-07-15T22:06:38Z","git_url":"git://github.com/google/oauth2client.git","ssh_url":"git@github.com:google/oauth2client.git","clone_url":"https://github.com/google/oauth2client.git","svn_url":"https://github.com/google/oauth2client","homepage":"","size":24596,"stargazers_count":392,"watchers_count":392,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":203,"mirror_url":null,"open_issues_count":87,"forks":203,"open_issues":87,"watchers":392,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/google/oauth2client/pulls/546"},"html":{"href":"https://github.com/google/oauth2client/pull/546"},"issue":{"href":"https://api.github.com/repos/google/oauth2client/issues/546"},"comments":{"href":"https://api.github.com/repos/google/oauth2client/issues/546/comments"},"review_comments":{"href":"https://api.github.com/repos/google/oauth2client/pulls/546/comments"},"review_comment":{"href":"https://api.github.com/repos/google/oauth2client/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/oauth2client/pulls/546/commits"},"statuses":{"href":"https://api.github.com/repos/google/oauth2client/statuses/08216201de0a4dd5f90ca1aa318dc7bde812bbc6"}}}}
{"actor":{"display_login":"waprin"}}