From 97495ba8a5896ca814c66fb0a2f16d799745331d Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 29 Jul 2020 13:42:03 +0200 Subject: [PATCH] Re-sync GitHub (RemoteRepository and RemoteOrganization) on webhook Add `member` event when creating the Read the Docs' webhook on each repository imported under Read the Docs. This webhook will communicate back to us when a collaborator was added/removed/changed from that repository in particular. This allow us to trigger the re-sync method for the GitHub service on that user and create/delete/change `RemoteRepository` objects for that user. Examples, * user is removed from having access to a repository -> remove RemoteRepository * user is added access to a repository -> create RemoteRepository * user is removed admin access but keep read access -> `.admin=False` --- readthedocs/api/v2/views/integrations.py | 14 ++++++++++++++ readthedocs/oauth/services/github.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/readthedocs/api/v2/views/integrations.py b/readthedocs/api/v2/views/integrations.py index 065b3edfb41..9a6b0113585 100644 --- a/readthedocs/api/v2/views/integrations.py +++ b/readthedocs/api/v2/views/integrations.py @@ -6,6 +6,9 @@ import logging import re +from allauth.socialaccount.providers.github.provider import GitHubProvider +from allauth.socialaccount.models import SocialAccount + from django.shortcuts import get_object_or_404 from rest_framework import permissions, status from rest_framework.exceptions import NotFound, ParseError @@ -33,6 +36,7 @@ GITHUB_EVENT_HEADER = 'HTTP_X_GITHUB_EVENT' GITHUB_SIGNATURE_HEADER = 'HTTP_X_HUB_SIGNATURE' +GITHUB_MEMBER = 'member' GITHUB_PUSH = 'push' GITHUB_PULL_REQUEST = 'pull_request' GITHUB_PULL_REQUEST_OPENED = 'opened' @@ -452,6 +456,16 @@ def handle_webhook(self): except KeyError: raise ParseError('Parameter "ref" is required') + # Re-sync repositories for the user if any permission has changed + if event == GITHUB_MEMBER: + uid = self.data.get('member').get('id') + socialaccount = SocialAccount.objects.get( + provider=GitHubProvider.id, + uid=uid, + ) + service = GitHubService(user=socialaccount.user, account=socialaccount) + service.sync() + return None def _normalize_ref(self, ref): diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index 366a3794092..0cafdf8393e 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -218,7 +218,7 @@ def get_webhook_data(self, project, integration): 'secret': integration.secret, 'content_type': 'json', }, - 'events': ['push', 'pull_request', 'create', 'delete'], + 'events': ['push', 'pull_request', 'create', 'delete', 'member'], }) def get_provider_data(self, project, integration):