{"action":"created","comment":{"url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/comments/74487916","id":74487916,"diff_hunk":"@@ -0,0 +1,164 @@\n+import urlparse\n+import uuid\n+\n+import functools\n+from django.apps import apps\n+from django.db import models\n+from osf_models.models import base\n+from osf_models.utils.base import api_v2_url\n+from osf_models.utils.security import random_string\n+\n+from framework.auth import cas\n+\n+generate_client_secret = functools.partial(random_string, length=40)\n+\n+\n+class ApiOAuth2Scope(base.ObjectIDMixin, base.BaseModel):\n+    \"\"\"\n+    Store information about recognized OAuth2 scopes. Only scopes registered under this database model can\n+        be requested by third parties.\n+    \"\"\"\n+    name = models.CharField(max_length=50, unique=True, db_index=True, null=False, blank=False)\n+    description = models.CharField(max_length=255, null=False, blank=False)\n+    is_active = models.BooleanField(default=True, db_index=True)  # TODO: Add mechanism to deactivate a scope?\n+\n+\n+class ApiOauth2Application(base.ObjectIDMixin, base.BaseModel):\n+    \"\"\"Registration and key for user-created OAuth API applications\n+\n+    This collection is also used by CAS to create the master list of available applications.\n+    Any changes made to field names in this model must be echoed in the CAS implementation.\n+    \"\"\"\n+\n+    # Client ID and secret. Use separate ID field so ID format doesn't have to be restricted to database internals.\n+    client_id = models.UUIDField(default=uuid.uuid4,  # Not *guaranteed* unique, but very unlikely\n+                                   unique=True,\n+                                   db_index=True)\n+\n+    client_secret = models.CharField(default=generate_client_secret, max_length=40)\n+\n+    is_active = models.BooleanField(default=True,  # Set to False if application is deactivated\n+                                    db_index=True)\n+\n+    owner = models.ForeignKey('OSFUser', null=False, blank=False)\n+\n+    # User-specified application descriptors\n+    name = models.CharField(db_index=True, blank=False, null=False, max_length=200)\n+    description = models.CharField(blank=True, null=True, max_length=1000)\n+\n+    date_created = models.DateTimeField(auto_now_add=True)\n+\n+    home_url = models.URLField(blank=False, null=False)\n+    callback_url = models.URLField(blank=False, null=False)\n+\n+    def deactivate(self, save=False):\n+        \"\"\"\n+        Deactivate an ApiOAuth2Application\n+\n+        Does not delete the database record, but revokes all tokens and sets a flag that hides this instance from API\n+        \"\"\"\n+        client = cas.get_client()\n+        # Will raise a CasHttpError if deletion fails, which will also stop setting of active=False.\n+        resp = client.revoke_application_tokens(self.client_id, self.client_secret)  # noqa\n+\n+        self.is_active = False\n+\n+        if save:\n+            self.save()\n+        return True\n+\n+    def reset_secret(self, save=False):\n+        \"\"\"\n+        Reset the secret of an ApiOAuth2Application\n+        Revokes all tokens\n+        \"\"\"\n+        client = cas.get_client()\n+        client.revoke_application_tokens(self.client_id, self.client_secret)\n+        self.client_secret = generate_client_secret()\n+\n+        if save:\n+            self.save()\n+        return True\n+\n+    @property\n+    def url(self):\n+        return '/settings/applications/{}/'.format(self.client_id)\n+\n+    @property\n+    def absolute_url(self):\n+        app_config = apps.get_containing_app_config(self)\n+        return urlparse.urljoin(app_config.domain, self.url)\n+\n+    # Properties used by Django and DRF \"Links: self\" field\n+    @property\n+    def absolute_api_v2_url(self):\n+        path = '/applications/{}/'.format(self.client_id)\n+        return api_v2_url(path)\n+\n+    # used by django and DRF\n+    def get_absolute_url(self):\n+        return self.absolute_api_v2_url\n+\n+\n+class ApiOAuth2PersonalToken(base.ObjectIDMixin, base.BaseModel):\n+    \"\"\"Information for user-created personal access tokens\n+\n+    This collection is also used by CAS to create the master list of available tokens.\n+    Any changes made to field names in this model must be echoed in the CAS implementation.\n+    \"\"\"\n+\n+    # Name of the field being `token_id` is a CAS requirement.\n+    # This is the actual value of the token that's used to authenticate\n+    token_id = models.CharField(max_length=70, default=functools.partial(random_string, length=70),\n+                                  unique=True)\n+\n+    owner = models.ForeignKey('OSFUser', db_index=True, blank=False, null=False)","path":"osf_models/models/oauth.py","position":115,"original_position":115,"commit_id":"5569627e9c6179f7de4af134e2a44a3bd5af173f","original_commit_id":"5569627e9c6179f7de4af134e2a44a3bd5af173f","user":{"login":"cwisecarver","id":3709,"avatar_url":"https://avatars.githubusercontent.com/u/3709?v=3","gravatar_id":"","url":"https://api.github.com/users/cwisecarver","html_url":"https://github.com/cwisecarver","followers_url":"https://api.github.com/users/cwisecarver/followers","following_url":"https://api.github.com/users/cwisecarver/following{/other_user}","gists_url":"https://api.github.com/users/cwisecarver/gists{/gist_id}","starred_url":"https://api.github.com/users/cwisecarver/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cwisecarver/subscriptions","organizations_url":"https://api.github.com/users/cwisecarver/orgs","repos_url":"https://api.github.com/users/cwisecarver/repos","events_url":"https://api.github.com/users/cwisecarver/events{/privacy}","received_events_url":"https://api.github.com/users/cwisecarver/received_events","type":"User","site_admin":false},"body":"Correct. I’ll fix it and start using it from now on.\n> On Aug 11, 2016, at 3:29 PM, Steven Loria <notifications@github.com> wrote:\n> \n> In osf_models/models/oauth.py <https://github.com/CenterForOpenScience/osf-models/pull/88#discussion_r74487449>:\n> \n> > +        return self.absolute_api_v2_url\n> > +\n> > +\n> > +class ApiOAuth2PersonalToken(base.ObjectIDMixin, base.BaseModel):\n> > +    \"\"\"Information for user-created personal access tokens\n> > +\n> > +    This collection is also used by CAS to create the master list of available tokens.\n> > +    Any changes made to field names in this model must be echoed in the CAS implementation.\n> > +    \"\"\"\n> > +\n> > +    # Name of the field being `token_id` is a CAS requirement.\n> > +    # This is the actual value of the token that's used to authenticate\n> > +    token_id = models.CharField(max_length=70, default=functools.partial(random_string, length=70),\n> > +                                  unique=True)\n> > +\n> > +    owner = models.ForeignKey('OSFUser', db_index=True, blank=False, null=False)\n> Minor: in future versions, on_delete will become a required argument. I think it should be set to SET_NULL here, yes?\n> \n> —\n> You are receiving this because you authored the thread.\n> Reply to this email directly, view it on GitHub <https://github.com/CenterForOpenScience/osf-models/pull/88/files/5569627e9c6179f7de4af134e2a44a3bd5af173f#r74487449>, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAAOfQKA_M1vlKvUbgVDzcUL5qFlUCEVks5qe3gVgaJpZM4JiawM>.\n> \n\n","created_at":"2016-08-11T19:32:19Z","updated_at":"2016-08-11T19:32:19Z","html_url":"https://github.com/CenterForOpenScience/osf-models/pull/88#discussion_r74487916","pull_request_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88","_links":{"self":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/comments/74487916"},"html":{"href":"https://github.com/CenterForOpenScience/osf-models/pull/88#discussion_r74487916"},"pull_request":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88"}}},"pull_request":{"url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88","id":81007946,"html_url":"https://github.com/CenterForOpenScience/osf-models/pull/88","diff_url":"https://github.com/CenterForOpenScience/osf-models/pull/88.diff","patch_url":"https://github.com/CenterForOpenScience/osf-models/pull/88.patch","issue_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/88","number":88,"state":"open","locked":false,"title":"[RFR] Add oauth related models","user":{"login":"cwisecarver","id":3709,"avatar_url":"https://avatars.githubusercontent.com/u/3709?v=3","gravatar_id":"","url":"https://api.github.com/users/cwisecarver","html_url":"https://github.com/cwisecarver","followers_url":"https://api.github.com/users/cwisecarver/followers","following_url":"https://api.github.com/users/cwisecarver/following{/other_user}","gists_url":"https://api.github.com/users/cwisecarver/gists{/gist_id}","starred_url":"https://api.github.com/users/cwisecarver/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cwisecarver/subscriptions","organizations_url":"https://api.github.com/users/cwisecarver/orgs","repos_url":"https://api.github.com/users/cwisecarver/repos","events_url":"https://api.github.com/users/cwisecarver/events{/privacy}","received_events_url":"https://api.github.com/users/cwisecarver/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-08-11T18:37:24Z","updated_at":"2016-08-11T19:32:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d0c20c305b655c7c594ba74fa56a548f5aa5c01d","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88/commits","review_comments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88/comments","review_comment_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/comments{/number}","comments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/88/comments","statuses_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/statuses/5569627e9c6179f7de4af134e2a44a3bd5af173f","head":{"label":"CenterForOpenScience:feature/oauth","ref":"feature/oauth","sha":"5569627e9c6179f7de4af134e2a44a3bd5af173f","user":{"login":"CenterForOpenScience","id":3344584,"avatar_url":"https://avatars.githubusercontent.com/u/3344584?v=3","gravatar_id":"","url":"https://api.github.com/users/CenterForOpenScience","html_url":"https://github.com/CenterForOpenScience","followers_url":"https://api.github.com/users/CenterForOpenScience/followers","following_url":"https://api.github.com/users/CenterForOpenScience/following{/other_user}","gists_url":"https://api.github.com/users/CenterForOpenScience/gists{/gist_id}","starred_url":"https://api.github.com/users/CenterForOpenScience/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CenterForOpenScience/subscriptions","organizations_url":"https://api.github.com/users/CenterForOpenScience/orgs","repos_url":"https://api.github.com/users/CenterForOpenScience/repos","events_url":"https://api.github.com/users/CenterForOpenScience/events{/privacy}","received_events_url":"https://api.github.com/users/CenterForOpenScience/received_events","type":"Organization","site_admin":false},"repo":{"id":54757593,"name":"osf-models","full_name":"CenterForOpenScience/osf-models","owner":{"login":"CenterForOpenScience","id":3344584,"avatar_url":"https://avatars.githubusercontent.com/u/3344584?v=3","gravatar_id":"","url":"https://api.github.com/users/CenterForOpenScience","html_url":"https://github.com/CenterForOpenScience","followers_url":"https://api.github.com/users/CenterForOpenScience/followers","following_url":"https://api.github.com/users/CenterForOpenScience/following{/other_user}","gists_url":"https://api.github.com/users/CenterForOpenScience/gists{/gist_id}","starred_url":"https://api.github.com/users/CenterForOpenScience/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CenterForOpenScience/subscriptions","organizations_url":"https://api.github.com/users/CenterForOpenScience/orgs","repos_url":"https://api.github.com/users/CenterForOpenScience/repos","events_url":"https://api.github.com/users/CenterForOpenScience/events{/privacy}","received_events_url":"https://api.github.com/users/CenterForOpenScience/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CenterForOpenScience/osf-models","description":"[in progress] Django models for the OSF","fork":false,"url":"https://api.github.com/repos/CenterForOpenScience/osf-models","forks_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/forks","keys_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/teams","hooks_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/hooks","issue_events_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/events{/number}","events_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/events","assignees_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/assignees{/user}","branches_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/branches{/branch}","tags_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/tags","blobs_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/refs{/sha}","trees_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/statuses/{sha}","languages_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/languages","stargazers_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/stargazers","contributors_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/contributors","subscribers_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/subscribers","subscription_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/subscription","commits_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/commits{/sha}","git_commits_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/commits{/sha}","comments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/comments{/number}","issue_comment_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/comments{/number}","contents_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/contents/{+path}","compare_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/merges","archive_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/downloads","issues_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues{/number}","pulls_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls{/number}","milestones_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/milestones{/number}","notifications_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/labels{/name}","releases_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/releases{/id}","deployments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/deployments","created_at":"2016-03-26T01:54:15Z","updated_at":"2016-07-18T18:59:19Z","pushed_at":"2016-08-11T19:24:44Z","git_url":"git://github.com/CenterForOpenScience/osf-models.git","ssh_url":"git@github.com:CenterForOpenScience/osf-models.git","clone_url":"https://github.com/CenterForOpenScience/osf-models.git","svn_url":"https://github.com/CenterForOpenScience/osf-models","homepage":"","size":331,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":48,"forks":2,"open_issues":48,"watchers":0,"default_branch":"master"}},"base":{"label":"CenterForOpenScience:master","ref":"master","sha":"fbc1db54ef81f2715778eb793ded145cff920df9","user":{"login":"CenterForOpenScience","id":3344584,"avatar_url":"https://avatars.githubusercontent.com/u/3344584?v=3","gravatar_id":"","url":"https://api.github.com/users/CenterForOpenScience","html_url":"https://github.com/CenterForOpenScience","followers_url":"https://api.github.com/users/CenterForOpenScience/followers","following_url":"https://api.github.com/users/CenterForOpenScience/following{/other_user}","gists_url":"https://api.github.com/users/CenterForOpenScience/gists{/gist_id}","starred_url":"https://api.github.com/users/CenterForOpenScience/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CenterForOpenScience/subscriptions","organizations_url":"https://api.github.com/users/CenterForOpenScience/orgs","repos_url":"https://api.github.com/users/CenterForOpenScience/repos","events_url":"https://api.github.com/users/CenterForOpenScience/events{/privacy}","received_events_url":"https://api.github.com/users/CenterForOpenScience/received_events","type":"Organization","site_admin":false},"repo":{"id":54757593,"name":"osf-models","full_name":"CenterForOpenScience/osf-models","owner":{"login":"CenterForOpenScience","id":3344584,"avatar_url":"https://avatars.githubusercontent.com/u/3344584?v=3","gravatar_id":"","url":"https://api.github.com/users/CenterForOpenScience","html_url":"https://github.com/CenterForOpenScience","followers_url":"https://api.github.com/users/CenterForOpenScience/followers","following_url":"https://api.github.com/users/CenterForOpenScience/following{/other_user}","gists_url":"https://api.github.com/users/CenterForOpenScience/gists{/gist_id}","starred_url":"https://api.github.com/users/CenterForOpenScience/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CenterForOpenScience/subscriptions","organizations_url":"https://api.github.com/users/CenterForOpenScience/orgs","repos_url":"https://api.github.com/users/CenterForOpenScience/repos","events_url":"https://api.github.com/users/CenterForOpenScience/events{/privacy}","received_events_url":"https://api.github.com/users/CenterForOpenScience/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CenterForOpenScience/osf-models","description":"[in progress] Django models for the OSF","fork":false,"url":"https://api.github.com/repos/CenterForOpenScience/osf-models","forks_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/forks","keys_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/teams","hooks_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/hooks","issue_events_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/events{/number}","events_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/events","assignees_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/assignees{/user}","branches_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/branches{/branch}","tags_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/tags","blobs_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/refs{/sha}","trees_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/statuses/{sha}","languages_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/languages","stargazers_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/stargazers","contributors_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/contributors","subscribers_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/subscribers","subscription_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/subscription","commits_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/commits{/sha}","git_commits_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/git/commits{/sha}","comments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/comments{/number}","issue_comment_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/comments{/number}","contents_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/contents/{+path}","compare_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/merges","archive_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/downloads","issues_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues{/number}","pulls_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls{/number}","milestones_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/milestones{/number}","notifications_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/labels{/name}","releases_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/releases{/id}","deployments_url":"https://api.github.com/repos/CenterForOpenScience/osf-models/deployments","created_at":"2016-03-26T01:54:15Z","updated_at":"2016-07-18T18:59:19Z","pushed_at":"2016-08-11T19:24:44Z","git_url":"git://github.com/CenterForOpenScience/osf-models.git","ssh_url":"git@github.com:CenterForOpenScience/osf-models.git","clone_url":"https://github.com/CenterForOpenScience/osf-models.git","svn_url":"https://github.com/CenterForOpenScience/osf-models","homepage":"","size":331,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":48,"forks":2,"open_issues":48,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88"},"html":{"href":"https://github.com/CenterForOpenScience/osf-models/pull/88"},"issue":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/88"},"comments":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/issues/88/comments"},"review_comments":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88/comments"},"review_comment":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/pulls/88/commits"},"statuses":{"href":"https://api.github.com/repos/CenterForOpenScience/osf-models/statuses/5569627e9c6179f7de4af134e2a44a3bd5af173f"}}}}
{"actor":{"display_login":"cwisecarver"}}