예제 #1
0
 def token_obj(self):
     if not hasattr(self, '_token_obj'):
         self._token_obj, _ = Token.get_or_connect(token=self.identifier.hget())
     return self._token_obj
예제 #2
0
 def manage_token(self, *args, **kwargs):
     from gim.core.limpyd_models import Token
     Token.update_token_from_gh(self, *args, **kwargs)
예제 #3
0
    def complete_auth(self):
        # check state
        attended_state = self.request.session.get('github-auth-state', None)
        if not attended_state:
            return False, "Unexpected request, please retry"
        del self.request.session['github-auth-state']

        state = self.request.GET.get('state', None)
        if state.strip() != attended_state.strip():
            return False, "Unexpected request, please retry"

        # get code
        code = self.request.GET.get('code', None)
        if not code:
            return False, "Authentication denied, please retry"

        # get the token for the given code
        try:
            gh = self.get_github_connection()
            token = gh.get_access_token(code)
        except:
            token = None

        if not token:
            return False, "Authentication failed, please retry"

        # do we have a user for this token ?
        try:
            user_with_token = GithubUser.objects.get(token=token)
        except GithubUser.DoesNotExist:
            user_with_token = None
        else:
            user_with_token.token = None
            user_with_token.save(update_fields=['token'])

        # get informations about this user
        try:
            user_infos = Connection(access_token=token).user.get()
        except:
            user_infos = None

        if not user_infos:
            return False, "Cannot get user informations, please retry"

        # create/update and get a user with the given infos and token
        try:
            user = GithubUser.objects.create_or_update_from_dict(
                                        data=user_infos,
                                        defaults={'simple': {'token': token}})
        except:
            return False, "Cannot save user informations, please retry"

        # reject banned users
        if not user.is_active:
            return False, "This account has been deactivated"

        # authenticate the user (needed to call login later)
        user = authenticate(username=user.username, token=user.token)
        if not user:
            return False, "Final authentication failed, please retry"

        # and finally login
        login(self.request, user)

        # set its username to the token
        user.token_object.username.hset(user.username)

        # remove other tokens for this username
        from gim.core.limpyd_models import Token
        for user_token in list(Token.collection(username=user.username).instances()):
            if user_token.token.hget() != token:
                user_token.delete()

        # add a job to fetch available repositories
        job = FetchAvailableRepositoriesJob.add_job(user.id, inform_user=1)

        if job.status == STATUSES.DELAYED:
            return True, "Authentication successful, welcome back!"
        else:
            return True, "Authentication successful, we are currently fetching repositories you can subscribe to (ones you own, collaborate to, or in your organizations)"
예제 #4
0
    def _get_gh(self):
        """
        Return a Connection object based on arguments saved in the job, or by
        type of permission, to get one from the Token model
        """
        from gim.core.limpyd_models import Token

        args = self.gh_args.hgetall()
        if "access_token" not in args:
            args = None

        permission = getattr(self, "permission", "read")

        token = None

        # we have connection args: get the token if available
        if args:
            try:
                token_kwargs = {"token": args["access_token"]}
                # ignore the available flag for "self"
                if permission != "self":
                    token_kwargs["available"] = 1
                try:
                    token = Token.get(**token_kwargs)
                except IndexError:
                    # changed during the "get"... retry once
                    # explanation: the get first check the length of the result
                    # and if it's 1, then it retrieves the first, but in the
                    # meantime, the data may have changed and there is result
                    # anymore...
                    token = Token.get(**token_kwargs)
                except:
                    raise
            except (Token.DoesNotExist, KeyError):
                pass
            else:
                # final check on remaining api calls
                if int(token.rate_limit_remaining.get() or 0):
                    return token.gh

        # no token, try to get one...
        repository = None

        if permission == "self":
            # forced to use the current one, but not available...
            pass
        else:

            # if we have a repository, get one following permission
            repository = getattr(self, "repository")
            if repository:
                if repository.private and permission not in ("admin", "push", "pull"):
                    # force correct permission if repository is private
                    permission = "pull"
                token = Token.get_one_for_repository(repository.pk, permission)

            # no repository, not "self", but want one ? don't know why but ok...
            else:
                token = Token.get_one()

        # if we don't have token it's that there is no one available: we delay
        # the job
        if not token:
            self.status.hset(STATUSES.DELAYED)

            if hasattr(self, "delay_for_gh"):
                # use the "delay_for_gh" attribute if any to delay the job for X seconds
                self.delayed_until.hset(compute_delayed_until(delayed_for=self.delay_for_gh))

            else:
                # check the first available gh
                if permission == "self":
                    if args:
                        try:
                            token = Token.get(token=args["access_token"])
                        except Token.DoesNotExist:
                            token = Token.get(username=args["username"])
                elif repository:
                    token = Token.get_one_for_repository(
                        repository.pk, permission, available=False, sort_by="rate_limit_reset"
                    )
                else:
                    token = Token.get_one(available=False, sort_by="rate_limit_reset")

                # if we have a token, get it's delay before availability, and
                # set it on the job for future use
                if token:

                    remaining = token.get_remaining_seconds()
                    if remaining is not None and remaining >= 0:
                        self.delayed_until.hset(compute_delayed_until(remaining))
                    else:
                        self.delayed_until.delete()

                    self.gh = token.gh

                else:
                    # no token at all ? we may have no one for this permission !
                    # so retry in 15mn
                    self.delayed_until.hset(compute_delayed_until(delayed_for=60 * 15))

            return None

        # save it in the job, useful when cloning to avoid searching for a new
        # gh (will only happen if it is not available anymore)
        self.gh = token.gh

        # and ok, return it
        return token.gh