(self)
- create any missing installations
        - add memberships of user for installations
        - remove memberships of installations that aren't included
def sync_accounts(self) -> None:
        """

        - create any missing installations
        - add memberships of user for installations
        - remove memberships of installations that aren't included
        """
        user_installations_res = requests.get(
            "https://api.github.com/user/installations",
            headers=dict(
                authorization=f"Bearer {self.github_access_token}",
                Accept="application/vnd.github.machine-man-preview+json",
            ),
            timeout=5,
        )
        try:
            user_installations_res.raise_for_status()
        except (requests.HTTPError, requests.exceptions.Timeout):
            logging.warning("sync_installation failed", exc_info=True)
            raise SyncAccountsError

        # TODO(chdsbd): Handle multiple pages of installations
        try:
            if user_installations_res.links["next"]:
                logging.warning("user has multiple pages")
        except KeyError:
            pass

        installations_data = user_installations_res.json()
        installations = installations_data["installations"]

        accounts: List[Account] = []

        for installation in installations:
            installation_id = installation["id"]
            installation_account_id = installation["account"]["id"]
            installation_account_login = installation["account"]["login"]
            installation_account_type = installation["account"]["type"]
            if installation_account_type == "Organization":
                account_membership_res = requests.get(
                    f"https://api.github.com/orgs/{installation_account_login}/memberships/{self.github_login}",
                    headers=dict(authorization=f"Bearer {self.github_access_token}"),
                    timeout=5,
                )
                try:
                    account_membership_res.raise_for_status()
                except requests.HTTPError:
                    # If the user is a collaborator instead of a member or admin
                    # of the organization, they won't have access and will get a
                    # 403 error.
                    logger.warning(
                        "problem fetching account membership response=%s, installation_account_login=%s user_github_login=%s",
                        account_membership_res,
                        installation_account_login,
                        self.github_login,
                    )
                    continue
                role = account_membership_res.json()["role"]
            elif (
                installation_account_type == "User"
                and installation_account_login == self.github_login
            ):
                role = "admin"
            else:
                role = "member"

            existing_account: Optional[Account] = Account.objects.filter(
                github_account_id=installation_account_id
            ).first()
            if existing_account is None:
                account = Account.objects.create(
                    github_installation_id=installation_id,
                    github_account_id=installation_account_id,
                    github_account_login=installation_account_login,
                    github_account_type=installation_account_type,
                )
            else:
                account = existing_account
                account.github_installation_id = installation_id
                account.github_account_id = installation_account_id
                account.github_account_login = installation_account_login
                account.github_account_type = installation_account_type
                account.save()

            try:
                account_membership = AccountMembership.objects.get(
                    account=account, user=self
                )
                account_membership.role = role
                account_membership.save()
            except AccountMembership.DoesNotExist:
                AccountMembership.objects.create(account=account, user=self, role=role)

            accounts.append(account)

        # remove installations to which the user no longer has access.
        AccountMembership.objects.exclude(account__in=accounts).filter(
            user=self
        ).delete()
def sync_accounts ( self ) -> None : user_installations_res = requests . get ( "https://api.github.com/user/installations" , headers = dict ( authorization = f"Bearer {self.github_access_token}" , Accept = "application/vnd.github.machine-man-preview+json" , ) , timeout = 5 , ) try : user_installations_res . raise_for_status ( ) except ( requests . HTTPError , requests . exceptions . Timeout ) : logging . warning ( "sync_installation failed" , exc_info = True ) raise SyncAccountsError # TODO(chdsbd): Handle multiple pages of installations try : if user_installations_res . links [ "next" ] : logging . warning ( "user has multiple pages" ) except KeyError : pass installations_data = user_installations_res . json ( ) installations = installations_data [ "installations" ] accounts : List [ Account ] = [ ] for installation in installations : installation_id = installation [ "id" ] installation_account_id = installation [ "account" ] [ "id" ] installation_account_login = installation [ "account" ] [ "login" ] installation_account_type = installation [ "account" ] [ "type" ] if installation_account_type == "Organization" : account_membership_res = requests . get ( f"https://api.github.com/orgs/{installation_account_login}/memberships/{self.github_login}" , headers = dict ( authorization = f"Bearer {self.github_access_token}" ) , timeout = 5 , ) try : account_membership_res . raise_for_status ( ) except requests . HTTPError : # If the user is a collaborator instead of a member or admin # of the organization, they won't have access and will get a # 403 error. logger . warning ( "problem fetching account membership response=%s, installation_account_login=%s user_github_login=%s" , account_membership_res , installation_account_login , self . github_login , ) continue role = account_membership_res . json ( ) [ "role" ] elif ( installation_account_type == "User" and installation_account_login == self . github_login ) : role = "admin" else : role = "member" existing_account : Optional [ Account ] = Account . objects . filter ( github_account_id = installation_account_id ) . first ( ) if existing_account is None : account = Account . objects . create ( github_installation_id = installation_id , github_account_id = installation_account_id , github_account_login = installation_account_login , github_account_type = installation_account_type , ) else : account = existing_account account . github_installation_id = installation_id account . github_account_id = installation_account_id account . github_account_login = installation_account_login account . github_account_type = installation_account_type account . save ( ) try : account_membership = AccountMembership . objects . get ( account = account , user = self ) account_membership . role = role account_membership . save ( ) except AccountMembership . DoesNotExist : AccountMembership . objects . create ( account = account , user = self , role = role ) accounts . append ( account ) # remove installations to which the user no longer has access. AccountMembership . objects . exclude ( account__in = accounts ) . filter ( user = self ) . delete ( )