Skip to content

Commit

Permalink
feat: Create a contributor list after generating codeowners
Browse files Browse the repository at this point in the history
Signed-off-by: John McBride <[email protected]>
  • Loading branch information
jpmcb committed Sep 5, 2024
1 parent 9468ed1 commit d7fa342
Show file tree
Hide file tree
Showing 10 changed files with 901 additions and 15 deletions.
14 changes: 12 additions & 2 deletions api/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ const (
codeChallengeLength = 87
sessionFileName = "session.json"

prodSupabaseURL = "https://fcqqkxwlntnrtjfbcioz.supabase.co"
prodSupabasePublicKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZjcXFreHdsbnRucnRqZmJjaW96Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTg0MTkyNzQsImV4cCI6MjAxMzk5NTI3NH0.ymWWYdnJC2gsnrJx4lZX2cfSOp-1xVuWFGt1Wr6zwtg"
prodSupabaseURL = "https://ibcwmlhcimymasokhgvn.supabase.co"
prodSupabasePublicKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImliY3dtbGhjaW15bWFzb2toZ3ZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTkyOTU1MzMsImV4cCI6MjAxNDg3MTUzM30.Mr-ucuNDBjy9BC7NJzOBBi0Qz8WYiKI4n0JtWr4_woY"

// TODO (jpmcb) - in the future, we'll want to encorporate the ability to
// authenticate to our beta auth service as well
Expand Down Expand Up @@ -177,6 +177,16 @@ func (a *Authenticator) CheckSession() error {
return nil
}

// GetSessionToken returns the access token for a given session
func (a *Authenticator) GetSessionToken() (string, error) {
session, err := a.readSessionFile()
if err != nil {
return "", fmt.Errorf("failed to read session file: %w", err)
}

return session.AccessToken, nil
}

// readSessionFile reads a session file and returns the session struct.
func (a *Authenticator) readSessionFile() (*session, error) {
configDir, err := config.GetConfigDirectory()
Expand Down
3 changes: 3 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/open-sauced/pizza-cli/api/services/contributors"
"github.com/open-sauced/pizza-cli/api/services/histogram"
"github.com/open-sauced/pizza-cli/api/services/repository"
"github.com/open-sauced/pizza-cli/api/services/workspaces"
)

// Client is the API client for OpenSauced API
Expand All @@ -15,6 +16,7 @@ type Client struct {
RepositoryService *repository.Service
ContributorService *contributors.Service
HistogramService *histogram.Service
WorkspacesService *workspaces.Service

// The configured http client for making API requests
httpClient *http.Client
Expand All @@ -40,6 +42,7 @@ func NewClient(endpoint string) *Client {
client.ContributorService = contributors.NewContributorsService(client.httpClient, client.endpoint)
client.RepositoryService = repository.NewRepositoryService(client.httpClient, client.endpoint)
client.HistogramService = histogram.NewHistogramService(client.httpClient, client.endpoint)
client.WorkspacesService = workspaces.NewWorkspacesService(client.httpClient, client.endpoint)

return &client
}
46 changes: 46 additions & 0 deletions api/services/workspaces/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package workspaces

import (
"time"

"github.com/open-sauced/pizza-cli/api/services"
)

type DbWorkspace struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Name string `json:"name"`
Description string `json:"description"`
IsPublic bool `json:"is_public"`
PayeeUserID *int `json:"payee_user_id"`
Members []DbWorkspaceMember `json:"members"`
}

type DbWorkspaceMember struct {
ID string `json:"id"`
UserID int `json:"user_id"`
WorkspaceID string `json:"workspace_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Role string `json:"role"`
}

type DbWorkspacesResponse struct {
Data []DbWorkspace `json:"data"`
Meta services.MetaData `json:"meta"`
}

type CreateWorkspaceRequestRepoInfo struct {
FullName string `json:"full_name"`
}

type CreateWorkspaceRequest struct {
Name string `json:"name"`
Description string `json:"description"`
Members []string `json:"members"`
Repos []CreateWorkspaceRequestRepoInfo `json:"repos"`
Contributors []string `json:"contributors"`
}
48 changes: 48 additions & 0 deletions api/services/workspaces/userlists/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package userlists

import (
"time"

"github.com/open-sauced/pizza-cli/api/services"
)

type DbUserListContributor struct {
ID string `json:"id"`
UserID int `json:"user_id"`
ListID string `json:"list_id"`
Username string `json:"username"`
CreatedAt time.Time `json:"created_at"`
}

type DbUserList struct {
ID string `json:"id"`
UserID int `json:"user_id"`
Name string `json:"name"`
IsPublic bool `json:"is_public"`
IsFeatured bool `json:"is_featured"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at"`
Contributors []DbUserListContributor `json:"contributors"`
}

type GetUserListsResponse struct {
Data []DbUserList `json:"data"`
Meta services.MetaData `json:"meta"`
}

type CreatePatchUserListRequest struct {
Name string `json:"name"`
IsPublic bool `json:"is_public"`
Contributors []CreateUserListRequestContributor `json:"contributors"`
}

type CreateUserListRequestContributor struct {
Login string `json:"login"`
}

type CreateUserListResponse struct {
ID string `json:"id"`
UserListID string `json:"user_list_id"`
WorkspaceID string `json:"workspace_id"`
}
191 changes: 191 additions & 0 deletions api/services/workspaces/userlists/userlists.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package userlists

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
)

// Service is used to access the "v2/workspaces/:workspaceId/userLists"
// endpoints and services
type Service struct {
httpClient *http.Client
endpoint string
}

// NewService returns a new UserListsService
func NewService(httpClient *http.Client, endpoint string) *Service {
return &Service{
httpClient: httpClient,
endpoint: endpoint,
}
}

// GetUserLists calls the "GET v2/workspaces/:workspaceId/userLists" endpoint
// for the authenticated user
func (uss *Service) GetUserLists(token string, workspaceID string, page, limit int) (*GetUserListsResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/workspaces/%s/userLists", uss.endpoint, workspaceID)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("page", fmt.Sprintf("%d", page))
q.Set("limit", fmt.Sprintf("%d", limit))
u.RawQuery = q.Encode()

req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, nil, fmt.Errorf("error creating request: %w", err)
}

req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

resp, err := uss.httpClient.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var userListsResp GetUserListsResponse
if err := json.NewDecoder(resp.Body).Decode(&userListsResp); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %w", err)
}

return &userListsResp, resp, nil
}

// GetUserList calls the "GET v2/workspaces/:workspaceId/userLists" endpoint
// for the authenticated user
func (uss *Service) GetUserList(token string, workspaceID string, userlistID string) (*DbUserList, *http.Response, error) {
url := fmt.Sprintf("%s/v2/workspaces/%s/userLists/%s", uss.endpoint, workspaceID, userlistID)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, nil, fmt.Errorf("error creating request: %w", err)
}

req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))

resp, err := uss.httpClient.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var userList DbUserList
if err := json.NewDecoder(resp.Body).Decode(&userList); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %w", err)
}

return &userList, resp, nil
}

// CreateUserListForUser calls the "POST v2/workspaces/:workspaceId/userLists" endpoint
// for the authenticated user
func (uss *Service) CreateUserListForUser(token string, workspaceID string, name string, logins []string) (*CreateUserListResponse, *http.Response, error) {
url := fmt.Sprintf("%s/v2/workspaces/%s/userLists", uss.endpoint, workspaceID)

loginReqs := []CreateUserListRequestContributor{}
for _, login := range logins {
loginReqs = append(loginReqs, CreateUserListRequestContributor{Login: login})
}

req := CreatePatchUserListRequest{
Name: name,
IsPublic: false,
Contributors: loginReqs,
}

payload, err := json.Marshal(req)
if err != nil {
return nil, nil, fmt.Errorf("error marshaling request: %w", err)
}

httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
if err != nil {
return nil, nil, fmt.Errorf("error creating request: %w", err)
}

httpReq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")

resp, err := uss.httpClient.Do(httpReq)
if err != nil {
return nil, resp, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var createdUserList CreateUserListResponse
if err := json.NewDecoder(resp.Body).Decode(&createdUserList); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %w", err)
}

return &createdUserList, resp, nil
}

// CreateUserListForUser calls the "PATCH v2/lists/:listId" endpoint
// for the authenticated user
func (uss *Service) PatchUserListForUser(token string, workspaceID string, listID string, name string, logins []string) (*DbUserList, *http.Response, error) {
url := fmt.Sprintf("%s/v2/workspaces/%s/userLists/%s", uss.endpoint, workspaceID, listID)

loginReqs := []CreateUserListRequestContributor{}
for _, login := range logins {
loginReqs = append(loginReqs, CreateUserListRequestContributor{Login: login})
}

req := CreatePatchUserListRequest{
Name: name,
IsPublic: false,
Contributors: loginReqs,
}

payload, err := json.Marshal(req)
if err != nil {
return nil, nil, fmt.Errorf("error marshaling request: %w", err)
}

httpReq, err := http.NewRequest("PATCH", url, bytes.NewBuffer(payload))
if err != nil {
return nil, nil, fmt.Errorf("error creating request: %w", err)
}

httpReq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")

resp, err := uss.httpClient.Do(httpReq)
if err != nil {
return nil, resp, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var createdUserList DbUserList
if err := json.NewDecoder(resp.Body).Decode(&createdUserList); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %w", err)
}

return &createdUserList, resp, nil
}
Loading

0 comments on commit d7fa342

Please sign in to comment.