예제 #1
0
class Twitter(PlatformOAuth1):

    # Platform attributes
    name = 'twitter'
    display_name = 'Twitter'
    account_url = 'https://twitter.com/{user_name}'

    # Auth attributes
    auth_url = 'https://api.twitter.com'
    authorize_path = '/oauth/authenticate'

    # API attributes
    api_format = 'json'
    api_paginator = query_param_paginator('cursor',
                                          prev='previous_cursor',
                                          next='next_cursor')
    api_url = 'https://api.twitter.com/1.1'
    api_user_info_path = '/users/show.json?user_id={user_id}'
    api_user_name_info_path = '/users/show.json?screen_name={user_name}'
    api_user_self_info_path = '/account/verify_credentials.json'
    api_friends_path = '/friends/list.json?user_id={user_id}&skip_status=true'
    ratelimit_headers_prefix = 'x-rate-limit-'

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('screen_name')
    x_display_name = key('name')
    x_email = not_available
    x_avatar_url = key('profile_image_url_https',
                       clean=lambda v: v.replace('_normal.', '.'))
    x_friends_count = key('friends_count')
예제 #2
0
class GitLab(PlatformOAuth2):

    # Platform attributes
    name = 'gitlab'
    display_name = 'GitLab'
    account_url = 'https://gitlab.com/u/{user_name}'

    # Auth attributes
    # GitLab uses https://github.com/doorkeeper-gem/doorkeeper
    auth_url = 'https://gitlab.com/oauth/authorize'
    access_token_url = 'https://gitlab.com/oauth/token'

    # API attributes
    # http://doc.gitlab.com/ce/api/
    api_format = 'json'
    api_paginator = header_links_paginator()
    api_url = 'https://gitlab.com/api/v3'
    # api_user_info_path = '/users/{user_id}'
    # api_user_name_info_path = '/users?username={user_name}'
    api_user_self_info_path = '/user'
    # api_team_members_path = '/groups/{user_name}/members'

    # The commented out paths are because we need this:
    # https://gitlab.com/gitlab-org/gitlab-ce/issues/13795

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('username')
    x_display_name = key('name')
    x_email = key('email')
    x_avatar_url = key('avatar_url')
예제 #3
0
class Google(PlatformOAuth2):

    # Platform attributes
    name = 'google'
    display_name = 'Google'
    account_url = 'https://plus.google.com/{user_id}'
    optional_user_name = True

    # Auth attributes
    auth_url = 'https://accounts.google.com/o/oauth2/auth'
    access_token_url = 'https://accounts.google.com/o/oauth2/token'
    oauth_default_scope = ['https://www.googleapis.com/auth/userinfo.email',
                           'https://www.googleapis.com/auth/plus.login']

    # API attributes
    api_format = 'json'
    api_paginator = query_param_paginator('pageToken',
                                          next='nextPageToken',
                                          page='items',
                                          total='totalItems')
    api_url = 'https://www.googleapis.com/plus/v1'
    api_user_info_path = '/people/{user_id}'
    api_user_self_info_path = '/people/me'
    api_friends_path = '/people/{user_id}/people/visible'
    api_friends_limited = True

    # User info extractors
    x_user_id = key('id')
    x_display_name = key('displayName')
    x_email = any_key(('emails', 0), clean=lambda d: d.get('value'))
    x_avatar_url = key('image', clean=lambda d: d.get('url'))

    def x_user_name(self, extracted, info, *default):
        url = info.get('url', '')
        return url[25:] if url.startswith('https://plus.google.com/+') else None
예제 #4
0
class Facebook(PlatformOAuth2):

    # Platform attributes
    name = 'facebook'
    display_name = 'Facebook'
    account_url = 'https://www.facebook.com/profile.php?id={user_id}'
    optional_user_name = True

    # Auth attributes
    auth_url = 'https://www.facebook.com/dialog/oauth'
    access_token_url = 'https://graph.facebook.com/oauth/access_token'
    oauth_default_scope = ['public_profile,email,user_friends']

    # API attributes
    api_format = 'json'
    api_paginator = keys_paginator('data', paging='paging', prev='previous')
    api_url = 'https://graph.facebook.com'
    api_user_name_info_path = '/{user_name}'
    api_user_self_info_path = '/me'
    api_friends_path = '/v2.2/{user_id}/friends'
    api_friends_limited = True

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('username')
    x_display_name = key('name')
    x_email = key('email')

    def x_avatar_url(self, extracted, info, default):
        return 'https://graph.facebook.com/' + extracted.user_id + '/picture?width=256&height=256'
예제 #5
0
class Facebook(PlatformOAuth2):

    # Platform attributes
    name = 'facebook'
    display_name = 'Facebook'
    fontawesome_name = 'facebook-square'
    account_url = 'https://www.facebook.com/app_scoped_user_id/{user_id}/'
    optional_user_name = True

    # Auth attributes
    auth_url = 'https://www.facebook.com/v2.10/dialog/oauth'
    access_token_url = 'https://graph.facebook.com/v2.10/oauth/access_token'
    refresh_token_url = None
    oauth_default_scope = ['public_profile']
    oauth_email_scope = 'email'
    oauth_friends_scope = 'user_friends'

    # API attributes
    api_format = 'json'
    api_paginator = keys_paginator('data', paging='paging', prev='previous')
    api_url = 'https://graph.facebook.com/v2.10'
    api_user_self_info_path = '/me?fields=id,name,email'
    api_friends_path = '/me/friends'
    api_friends_limited = True

    # User info extractors
    x_user_id = key('id')
    x_display_name = key('name')
    x_email = key('email')
    x_description = key('bio')

    def x_avatar_url(self, extracted, info, default):
        return 'https://graph.facebook.com/' + extracted.user_id + '/picture?width=256&height=256'
예제 #6
0
class Bountysource(Platform):

    # Platform attributes
    name = 'bountysource'
    display_name = 'Bountysource'
    account_url = '{platform_data.auth_url}/people/{user_id}'
    optional_user_name = True

    # API attributes
    api_format = 'json'
    api_user_info_path = '/users/{user_id}'
    api_user_self_info_path = '/user'

    # User info extractors
    x_user_id = key('id')
    x_user_name = not_available
    x_display_name = key('display_name')
    x_email = key('email')
    x_avatar_url = key('image_url')

    def get_auth_session(self, token=None):
        sess = requests.Session()
        sess.auth = BountysourceAuth(token)
        return sess

    def get_auth_url(self, user):
        query_id = hexlify(os.urandom(10))
        time_now = int(time())
        raw = '%s.%s.%s' % (user.id, time_now, self.api_secret)
        h = hashlib.md5(raw).hexdigest()
        token = '%s.%s.%s' % (user.id, time_now, h)
        params = dict(redirect_url=self.callback_url + '?query_id=' + query_id,
                      external_access_token=token)
        url = self.auth_url + '/auth/liberapay/confirm?' + urlencode(params)
        return url, query_id, ''

    def get_query_id(self, querystring):
        token = querystring['access_token']
        i = token.rfind('.')
        data, data_hash = token[:i], token[i + 1:]
        if data_hash != hashlib.md5(data + '.' + self.api_secret).hexdigest():
            raise Response(400, 'Invalid hash in access_token')
        return querystring['query_id']

    def get_user_self_info(self, sess):
        querystring = urlparse(sess._callback_url).query
        info = {
            k: v[0] if len(v) == 1 else v
            for k, v in parse_qs(querystring).items()
        }
        info.pop('access_token')
        info.pop('query_id')
        return self.extract_user_info(info)

    def handle_auth_callback(self, url, query_id, unused_arg):
        sess = self.get_auth_session(token=query_id)
        sess._callback_url = url
        return sess
예제 #7
0
class Youtube(PlatformOAuth2):

    # Platform attributes
    based_on = 'google'
    name = 'youtube'
    display_name = 'Youtube'
    account_url = 'https://youtube.com/channel/{user_id}'
    optional_user_name = True
    user_type = 'channel'

    # Auth attributes
    auth_url = 'https://accounts.google.com/o/oauth2/auth?access_type=offline'
    access_token_url = 'https://accounts.google.com/o/oauth2/token'
    oauth_default_scope = ['https://www.googleapis.com/auth/youtube.readonly']

    # API attributes
    api_format = 'json'
    api_paginator = query_param_paginator('pageToken',
                                          next='nextPageToken',
                                          page='items',
                                          total=('pageInfo', 'totalResults'))
    api_url = 'https://www.googleapis.com/youtube/v3'
    api_user_info_path = '/channels?part=snippet&id={user_id}'
    api_user_self_info_path = '/channels?part=snippet&mine=true'
    api_friends_path = '/subscriptions?part=snippet&mine=true'
    api_search_path = '/search?part=snippet&type=channel&q={query}'

    # User info extractors
    x_user_info = key('items')
    x_user_id = any_key(('snippet', 'resourceId', 'channelId'), 'id')
    x_display_name = any_key(('snippet', 'title'))
    x_avatar_url = any_key(('snippet', 'thumbnails', 'medium', 'url'))
    x_description = any_key(('snippet', 'description'))
예제 #8
0
class Bitbucket(PlatformOAuth1):

    # Platform attributes
    name = 'bitbucket'
    display_name = 'Bitbucket'
    fontawesome_name = name
    account_url = 'https://bitbucket.org/{user_name}'

    # Auth attributes
    auth_url = 'https://bitbucket.org/api/1.0'
    authorize_path = '/oauth/authenticate'

    # API attributes
    api_format = 'json'
    api_paginator = keys_paginator('values', prev='previous', total='size')
    api_url = 'https://bitbucket.org/api'
    api_user_info_path = '/2.0/users/{user_id}'
    api_user_name_info_path = '/2.0/users/{user_name}'
    api_user_self_info_path = '/2.0/user'
    api_team_members_path = '/2.0/teams/{user_name}/members'
    api_friends_path = '/2.0/users/{user_name}/following'

    # User info extractors
    x_user_info = key('user')
    x_user_id = key('uuid')
    x_user_name = key('username')
    x_display_name = key('display_name')
    x_email = not_available
    x_avatar_url = any_key('avatar', ('links', 'avatar', 'href'))
    x_is_team = key('type', lambda v: v == 'team')

    def api_get(self, domain, path, sess=None, **kw):
        """Extend to manually retry /users/pypy as /teams/pypy.

        Bitbucket gives us a 404 where a 30x would be more helpful.

        """
        try:
            return PlatformOAuth1.api_get(self, domain, path, sess, **kw)
        except Response as response:
            if response.code == 404 and ' is a team account' in response.body:
                assert path.startswith('/2.0/users/')
                path = '/2.0/teams/' + path[11:]
                return PlatformOAuth1.api_get(self, domain, path, sess, **kw)
            else:
                raise
예제 #9
0
class Autour(PlatformOAuth2):

    # Platform attributes
    name = 'autour'
    display_name = 'Autour.com'
    account_url = 'https://autour.com/{user_name}'
    allows_team_connect = True

    # Auth attributes
    auth_url = 'https://api.autour.com/oauth2'
    access_token_url = 'https://api.autour.com/oauth2/access_token'
    oauth_email_scope = 'user:email'
    oauth_default_scope = ['read:org']

    # API attributes
    api_format = 'json'
    api_paginator = header_links_paginator()
    api_url = 'https://api.autour.com'
    api_app_auth_params = 'client_id={api_key}&client_secret={api_secret}'
    api_friends_path = '/friends/{user_name}'
    api_user_info_path = '/users/{user_name}'
    api_user_name_info_path = '/users/{user_name}'
    api_user_self_info_path = '/oauth2/verify_credentials'
    api_team_members_path = '/orgs/{user_name}/public_members'
    api_friends_path = '/users/{user_id}/following'
    ratelimit_headers_prefix = 'x-ratelimit-'

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('login')
    x_display_name = key('name')
    x_email = key('email')
    x_gravatar_id = key('gravatar_id')
    x_avatar_url = key('avatar_url')
    x_is_team = key('type', clean=lambda t: t.lower() == 'organization')
예제 #10
0
class Twitch(PlatformOAuth2):

    # Platform attributes
    name = 'twitch'
    display_name = 'Twitch'
    account_url = 'https://twitch.tv/{user_name}'
    user_type = 'channel'

    # Auth attributes
    auth_url = 'https://api.twitch.tv/kraken/oauth2/authorize'
    access_token_url = 'https://api.twitch.tv/kraken/oauth2/token'
    oauth_default_scope = ['channel_read']
    session_class = TwitchOAuthSession

    # API attributes
    api_headers = {'Accept': 'application/vnd.twitchtv.v5+json'}
    api_format = 'json'
    api_paginator = query_param_paginator('cursor',
                                          next='_cursor',
                                          total='_total')
    api_url = 'https://api.twitch.tv/kraken'
    api_user_info_path = '/channels/{user_id}'
    api_user_self_info_path = '/channel'
    api_friends_path = '/users/{user_id}/follows/channels'
    api_search_path = '/search/channels?query={query}'

    # User info extractors
    x_user_info = key('channel')
    x_user_id = key('_id')
    x_user_name = key('name')
    x_display_name = key('display_name')
    x_email = key('email')
    x_avatar_url = key('logo')
    x_description = key('description')
예제 #11
0
class LinuxFr(PlatformOAuth2):

    # Platform attributes
    name = 'linuxfr'
    display_name = 'LinuxFr.org'
    account_url = 'https://linuxfr.org/users/{user_name_lower}'

    # Auth attributes
    # LinuxFr uses https://github.com/doorkeeper-gem/doorkeeper
    auth_url = 'https://linuxfr.org/api/oauth/authorize'
    access_token_url = 'https://linuxfr.org/api/oauth/token'

    # API attributes
    # https://linuxfr.org/developpeur
    api_format = 'json'
    api_url = 'https://linuxfr.org/api/v1'
    api_user_self_info_path = '/me'

    # User info extractors
    x_user_name = key('login')
    x_email = key('email')
예제 #12
0
class Google(PlatformOAuth2):

    # Platform attributes
    name = 'google'
    display_name = 'Google'
    fontawesome_name = name
    account_url = None
    optional_user_name = True

    # Auth attributes
    # https://developers.google.com/identity/protocols/OAuth2WebServer
    auth_url = 'https://accounts.google.com/o/oauth2/auth?access_type=offline&include_granted_scopes=true'
    access_token_url = 'https://accounts.google.com/o/oauth2/token'
    # https://developers.google.com/identity/protocols/googlescopes
    oauth_default_scope = ['https://www.googleapis.com/auth/userinfo.profile']
    oauth_friends_scope = 'https://www.googleapis.com/auth/contacts.readonly'

    # https://developers.google.com/people/api/rest/v1/people/get
    person_fields = 'personFields=names,nicknames,photos,taglines'

    # API attributes
    api_requires_user_token = True
    api_format = 'json'
    api_paginator = query_param_paginator('pageToken',
                                          next='nextPageToken',
                                          total='totalItems')
    api_url = 'https://people.googleapis.com/v1'
    api_user_info_path = '/people/{user_id}?%s' % person_fields
    api_user_self_info_path = '/people/me?%s' % person_fields
    api_friends_path = '/people/me/connections?%s' % person_fields

    # User info extractors
    x_user_id = key('resourceName', clean=partial(_strip_prefix, 'people/'))
    x_display_name = any_key(('names', 'displayName'))
    x_avatar_url = any_key('coverPhotos',
                           'photos',
                           clean=lambda d: None
                           if d.get('default') else d['url'])
    x_description = any_key(('taglines', 'value'))

    def x_user_info(self, extracted, info, *default):
        """Reduce a Person object to its primary values.

        Docs: https://developers.google.com/people/api/rest/v1/people#Person
        """
        for k, v in list(info.items()):
            if type(v) is list:
                info[k] = get_primary(v)
        return info
예제 #13
0
class Twitch(PlatformOAuth2):

    # Platform attributes
    name = 'twitch'
    display_name = 'Twitch'
    fontawesome_name = name
    account_url = 'https://twitch.tv/{user_name}'
    user_type = 'channel'

    # Auth attributes
    # https://dev.twitch.tv/docs/authentication/
    auth_url = 'https://id.twitch.tv/oauth2/authorize'
    access_token_url = 'https://id.twitch.tv/oauth2/token'
    can_auth_with_client_credentials = True

    # API attributes
    api_format = 'json'
    api_paginator = cursor_paginator(('pagination', 'cursor'),
                                     page='data',
                                     next='after',
                                     prev='before')
    api_url = 'https://api.twitch.tv/helix'
    api_user_info_path = '/users?id={user_id}'
    api_user_name_info_path = '/users?login={user_name}'
    api_user_self_info_path = '/users'

    # api_friends_path = '/users/follows?from_id={user_id}'
    # This endpoint only returns user IDs, not a list of user info objects

    # User info extractors
    x_user_info = key('data')
    x_user_id = key('id')
    x_user_name = key('login')
    x_display_name = key('display_name')
    x_email = key('email')
    x_avatar_url = key('profile_image_url')
    x_description = key('description')

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        self.api_headers = {'Client-ID': self.api_key}
예제 #14
0
class GitHub(PlatformOAuth2):

    # Platform attributes
    name = 'github'
    display_name = 'GitHub'
    account_url = 'https://github.com/{user_name}'
    allows_team_connect = True

    # Auth attributes
    auth_url = 'https://github.com/login/oauth/authorize'
    access_token_url = 'https://github.com/login/oauth/access_token'
    oauth_email_scope = 'user:email'
    oauth_default_scope = ['read:org']

    # API attributes
    api_format = 'json'
    api_paginator = header_links_paginator()
    api_url = 'https://api.github.com'
    api_user_info_path = '/user/{user_id}'
    api_user_name_info_path = '/users/{user_name}'
    api_user_self_info_path = '/user'
    api_team_members_path = '/orgs/{user_name}/public_members'
    api_friends_path = '/users/{user_name}/following'
    ratelimit_headers_prefix = 'x-ratelimit-'

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('login')
    x_display_name = key('name')
    x_email = key('email')
    x_gravatar_id = key('gravatar_id')
    x_avatar_url = key('avatar_url')
    x_is_team = key('type', clean=lambda t: t.lower() == 'organization')

    def is_team_admin(self, team_name, sess):
        user_teams = self.api_parser(self.api_get('/user/teams', sess=sess))
        return any(
            team.get('organization', {}).get('login') == team_name
            and team.get('permission') == 'admin' for team in user_teams)
예제 #15
0
class Twitch(PlatformOAuth2):

    # Platform attributes
    name = 'twitch'
    display_name = 'Twitch'
    account_url = 'https://twitch.tv/{user_name}'
    user_type = 'channel'

    # Auth attributes
    # https://dev.twitch.tv/docs/authentication/
    auth_url = 'https://id.twitch.tv/oauth2/authorize'
    access_token_url = 'https://id.twitch.tv/oauth2/token'
    can_auth_with_client_credentials = True

    # API attributes
    api_format = 'json'
    api_paginator = cursor_paginator(('pagination', 'cursor'),
                                     page='data',
                                     next='after',
                                     prev='before')
    api_url = 'https://api.twitch.tv/helix'
    api_user_info_path = '/users?id={user_id}'
    api_user_name_info_path = '/users?login={user_name}'
    api_user_self_info_path = '/users'

    # api_friends_path = '/users/follows?from_id={user_id}'
    # This endpoint only returns user IDs, not a list of user info objects

    # User info extractors
    x_user_info = key('data',
                      clean=lambda o: o[0]
                      if isinstance(o, list) and len(o) == 1 else o)
    x_user_id = key('id')
    x_user_name = key('login')
    x_display_name = key('display_name')
    x_email = key('email')
    x_avatar_url = key('profile_image_url')
    x_description = key('description')
예제 #16
0
class GitHub(PlatformOAuth2):

    # Platform attributes
    name = 'github'
    display_name = 'GitHub'
    account_url = 'https://github.com/{user_name}'
    repo_url = 'https://github.com/{slug}'
    has_teams = True

    # Auth attributes
    auth_url = 'https://github.com/login/oauth/authorize'
    access_token_url = 'https://github.com/login/oauth/access_token'
    oauth_email_scope = 'user:email'
    oauth_default_scope = ['read:org']

    # API attributes
    api_format = 'json'
    api_paginator = header_links_paginator()
    api_url = 'https://api.github.com'
    api_app_auth_params = 'client_id={api_key}&client_secret={api_secret}'
    api_user_info_path = '/user/{user_id}'
    api_user_name_info_path = '/users/{user_name}'
    api_user_self_info_path = '/user'
    api_team_members_path = '/orgs/{user_name}/public_members'
    api_friends_path = '/users/{user_name}/following'
    api_repos_path = '/users/{user_name}/repos?type=owner&sort=updated&per_page=100'
    api_starred_path = '/users/{user_name}/starred'
    ratelimit_headers_prefix = 'x-ratelimit-'

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('login')
    x_display_name = key('name')
    x_email = key('email')
    x_gravatar_id = key('gravatar_id')
    x_avatar_url = key('avatar_url')
    x_is_team = key('type', clean=lambda t: t.lower() == 'organization')

    # Repo info extractors
    x_repo_id = key('id')
    x_repo_name = key('name')
    x_repo_slug = key('full_name')
    x_repo_description = key('description')
    x_repo_last_update = key('updated_at')
    x_repo_is_fork = key('fork')
    x_repo_stars_count = key('stargazers_count')
    x_repo_owner_id = key('owner', clean=lambda d: d['id'])
    x_repo_extra_info_drop = drop_keys(lambda k: k.endswith('_url'))

    def get_CantReadMembership_url(self, **kw):
        return 'https://github.com/settings/connections/applications/' + self.api_key

    def is_team_member(self, org_name, sess, account):
        org_name = org_name.lower()

        # Check public membership first
        response = self.api_get('',
                                '/orgs/' + org_name + '/public_members/' +
                                account.user_name,
                                sess=sess,
                                error_handler=None)
        if response.status_code == 204:
            return True
        elif response.status_code != 404:
            self.api_error_handler(response, True, self.domain)

        # Check private membership
        response = self.api_get('',
                                '/user/memberships/orgs/' + org_name,
                                sess=sess,
                                error_handler=None)
        if response.status_code == 403:
            raise CantReadMembership
        elif response.status_code >= 400:
            self.api_error_handler(response, True, self.domain)
        membership = self.api_parser(response)
        if membership['state'] == 'active':
            return True

        # Try the endpoint we were using before
        user_orgs = self.api_parser(self.api_get('', '/user/orgs', sess=sess))
        return any(org.get('login') == org_name for org in user_orgs)
예제 #17
0
class GitLab(PlatformOAuth2):

    # Platform attributes
    name = 'gitlab'
    display_name = 'GitLab'
    account_url = 'https://gitlab.com/u/{user_name}'
    repo_url = 'https://gitlab.com/{slug}'
    has_teams = True

    # Auth attributes
    # GitLab uses https://github.com/doorkeeper-gem/doorkeeper
    auth_url = 'https://gitlab.com/oauth/authorize'
    access_token_url = 'https://gitlab.com/oauth/token'
    can_auth_with_client_credentials = True

    # API attributes
    # http://doc.gitlab.com/ce/api/
    api_format = 'json'
    api_paginator = header_links_paginator(total_header='X-Total')
    api_url = 'https://gitlab.com/api/v3'
    # api_user_info_path = '/users/{user_id}'
    # api_user_name_info_path = '/users?username={user_name}'
    api_user_self_info_path = '/user'
    # api_team_members_path = '/groups/{user_name}/members'
    api_repos_path = '/projects?owned=true&visibility=public&order_by=last_activity_at&per_page=100'
    api_starred_path = '/projects?starred=true&visibility=public'

    # The commented out paths are because we need this:
    # https://gitlab.com/gitlab-org/gitlab-ce/issues/13795

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('username')
    x_display_name = key('name')
    x_email = key('email')
    x_avatar_url = key('avatar_url')

    # Repo info extractors
    x_repo_id = key('id')
    x_repo_name = key('name')
    x_repo_slug = key('path_with_namespace')
    x_repo_description = key('description')
    x_repo_last_update = key('last_activity_at')
    x_repo_is_fork = key('forked_from_project', clean=bool)
    x_repo_stars_count = key('star_count')
    x_repo_owner_id = key('owner', clean=lambda d: d['id'])
예제 #18
0
class GitLab(PlatformOAuth2):

    # Platform attributes
    name = 'gitlab'
    display_name = 'GitLab'
    fontawesome_name = name
    account_url = 'https://gitlab.com/{user_name}'
    repo_url = 'https://gitlab.com/{slug}'
    has_teams = True

    # Auth attributes
    # GitLab uses https://github.com/doorkeeper-gem/doorkeeper
    auth_url = 'https://gitlab.com/oauth/authorize'
    access_token_url = 'https://gitlab.com/oauth/token'
    oauth_default_scope = ['read_user']

    # can_auth_with_client_credentials = True
    # https://gitlab.com/gitlab-org/gitlab-ce/issues/13795

    # API attributes
    # http://doc.gitlab.com/ce/api/
    api_format = 'json'
    api_paginator = header_links_paginator(total_header='X-Total')
    api_url = 'https://gitlab.com/api/v4'
    api_user_info_path = '/users/{user_id}'
    api_user_name_info_path = '/users?username={user_name}'
    api_user_self_info_path = '/user'
    api_team_members_path = '/groups/{user_name}/members'
    api_repos_path = APIEndpoint(
        '/users/{user_id}/projects?owned=true&visibility=public&order_by=last_activity_at&per_page=100',
        use_session=False)
    api_starred_path = APIEndpoint(
        '/users/{user_id}/projects?starred=true&visibility=public',
        use_session=False)

    # User info extractors
    x_user_id = key('id')
    x_user_name = key('username')
    x_display_name = key('name')
    x_email = key('email')
    x_avatar_url = key('avatar_url')
    x_description = key('bio')

    # Repo info extractors
    x_repo_id = key('id')
    x_repo_name = key('name')
    x_repo_slug = key('path_with_namespace')
    x_repo_description = key('description')
    x_repo_last_update = key('last_activity_at')
    x_repo_is_fork = key('forked_from_project', clean=bool)
    x_repo_stars_count = key('star_count')
예제 #19
0
class Mastodon(PlatformOAuth2):

    # Platform attributes
    name = 'mastodon'
    display_name = 'Mastodon'
    account_url = 'https://{domain}/@{user_name}'
    single_domain = False

    def example_account_address(self, _):
        return _('*****@*****.**')

    # Auth attributes
    # Mastodon uses https://github.com/doorkeeper-gem/doorkeeper
    auth_url = 'https://{domain}/oauth/authorize'
    access_token_url = 'https://{domain}/oauth/token'
    can_auth_with_client_credentials = True

    # API attributes
    # https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md
    api_format = 'json'
    api_paginator = header_links_paginator()
    api_url = 'https://{domain}/api/v1'
    api_user_info_path = '/accounts/{user_id}'
    # api_user_name_info_path = '/search?q={user_name}@{domain}'
    api_user_self_info_path = '/accounts/verify_credentials'
    api_friends_path = '/accounts/{user_id}/following'
    ratelimit_headers_prefix = 'x-ratelimit-'

    # User info extractors
    x_domain = key('url', clean=extract_domain_from_url)
    x_user_id = key('id')
    x_user_name = key('username')
    x_display_name = key('display_name')
    x_avatar_url = key('avatar_static')

    def x_user_info(self, extracted, info, default):
        if 'accounts' in info:
            accounts = info.get('accounts')
            if accounts:
                return accounts[0]
            raise Response(404)
        return default

    def register_app(self, domain):
        data = {
            'client_name': self.app_name,
            'redirect_uris': self.callback_url.format(domain=domain),
            'scopes': 'read',
            'website': self.app_url,
        }
        r = requests.post('https://%s/api/v1/apps' % domain, data, timeout=self.api_timeout)
        status = r.status_code
        try:
            o = r.json()
            c_id, c_secret = o['client_id'], o['client_secret']
        except (KeyError, ValueError):
            c_id, c_secret = None, None
        if status != 200 or not c_id or not c_secret:
            logger.error('{} responded with {}:\n{}'.format(domain, status, r.text))
            msg = lambda _: _(
                "Is {0} really a {1} server? It is currently not acting like one.",
                domain, self.display_name,
            )
            raise LazyResponse(502, msg)
        return c_id, c_secret