short-d/short

View on GitHub
backend/app/adapter/github/account.go

Summary

Maintainability
A
0 mins
Test Coverage
package github

import (
    "errors"
    "fmt"

    "github.com/short-d/app/fw/graphql"
    "github.com/short-d/short/backend/app/entity"
    "github.com/short-d/short/backend/app/usecase/sso"
)

const githubAPI = "https://api.github.com/graphql"

var _ sso.Account = (*Account)(nil)

// Account accesses user's account data through Github API v4.
type Account struct {
    gqlClient graphql.Client
}

// GetSingleSignOnUser retrieves user's email and name from Github.
func (a Account) GetSingleSignOnUser(accessToken string) (entity.SSOUser, error) {
    type response struct {
        Viewer struct {
            ID    string `json:"id"`
            Email string `json:"email"`
            Name  string `json:"name"`
        } `json:"viewer"`
    }

    var profileResponse response
    query := graphql.Query{
        Query: `
query {
    viewer {
        id
        email
        name
    }
}
`,
        Variables: nil,
    }

    err := a.sendGraphQLRequest(accessToken, query, &profileResponse)
    if err != nil {
        return entity.SSOUser{}, err
    }

    if profileResponse.Viewer.ID == "" {
        return entity.SSOUser{}, errors.New("user ID can't be empty")
    }

    return entity.SSOUser{
        ID:    profileResponse.Viewer.ID,
        Email: profileResponse.Viewer.Email,
        Name:  profileResponse.Viewer.Name,
    }, nil
}

func (a Account) sendGraphQLRequest(accessToken string, query graphql.Query, response interface{}) error {
    headers := map[string]string{
        "Authorization": fmt.Sprintf("bearer %s", accessToken),
    }
    return a.gqlClient.Query(query, headers, response)
}

// NewAccount initializes Github account API client.
func NewAccount(gqlClientFactory graphql.ClientFactory) Account {
    return Account{
        gqlClient: gqlClientFactory.NewClient(githubAPI),
    }
}