2
0
Alexander Belanger 5 жил өмнө
parent
commit
841ff04c95

+ 2 - 0
internal/repository/gitrepo.go

@@ -8,4 +8,6 @@ type GitRepoRepository interface {
 	CreateGitRepo(gr *models.GitRepo) (*models.GitRepo, error)
 	CreateGitRepo(gr *models.GitRepo) (*models.GitRepo, error)
 	ReadGitRepo(id uint) (*models.GitRepo, error)
 	ReadGitRepo(id uint) (*models.GitRepo, error)
 	ListGitReposByProjectID(projectID uint) ([]*models.GitRepo, error)
 	ListGitReposByProjectID(projectID uint) ([]*models.GitRepo, error)
+	UpdateGitRepo(gr *models.GitRepo) (*models.GitRepo, error)
+	DeleteGitRepo(gr *models.GitRepo) error
 }
 }

+ 29 - 5
internal/repository/gorm/gitrepo.go

@@ -19,7 +19,7 @@ func NewGitRepoRepository(db *gorm.DB, key *[32]byte) repository.GitRepoReposito
 	return &GitRepoRepository{db, key}
 	return &GitRepoRepository{db, key}
 }
 }
 
 
-// CreateGitRepo creates a new repo client and appends it to the in-memory list
+// CreateGitRepo creates a new git repo
 func (repo *GitRepoRepository) CreateGitRepo(gr *models.GitRepo) (*models.GitRepo, error) {
 func (repo *GitRepoRepository) CreateGitRepo(gr *models.GitRepo) (*models.GitRepo, error) {
 	project := &models.Project{}
 	project := &models.Project{}
 
 
@@ -40,11 +40,10 @@ func (repo *GitRepoRepository) CreateGitRepo(gr *models.GitRepo) (*models.GitRep
 	return gr, nil
 	return gr, nil
 }
 }
 
 
-// ReadGitRepo returns a repo client by id
+// ReadGitRepo gets a git repo specified by a unique id
 func (repo *GitRepoRepository) ReadGitRepo(id uint) (*models.GitRepo, error) {
 func (repo *GitRepoRepository) ReadGitRepo(id uint) (*models.GitRepo, error) {
 	gr := &models.GitRepo{}
 	gr := &models.GitRepo{}
 
 
-	// preload Clusters association
 	if err := repo.db.Where("id = ?", id).First(&gr).Error; err != nil {
 	if err := repo.db.Where("id = ?", id).First(&gr).Error; err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -52,8 +51,11 @@ func (repo *GitRepoRepository) ReadGitRepo(id uint) (*models.GitRepo, error) {
 	return gr, nil
 	return gr, nil
 }
 }
 
 
-// ListGitReposByProjectID returns a list of repo clients that match a project id
-func (repo *GitRepoRepository) ListGitReposByProjectID(projectID uint) ([]*models.GitRepo, error) {
+// ListGitReposByProjectID finds all git repos
+// for a given project id
+func (repo *GitRepoRepository) ListGitReposByProjectID(
+	projectID uint,
+) ([]*models.GitRepo, error) {
 	grs := []*models.GitRepo{}
 	grs := []*models.GitRepo{}
 
 
 	if err := repo.db.Where("project_id = ?", projectID).Find(&grs).Error; err != nil {
 	if err := repo.db.Where("project_id = ?", projectID).Find(&grs).Error; err != nil {
@@ -62,3 +64,25 @@ func (repo *GitRepoRepository) ListGitReposByProjectID(projectID uint) ([]*model
 
 
 	return grs, nil
 	return grs, nil
 }
 }
+
+// UpdateGitRepo modifies an existing GitRepo in the database
+func (repo *GitRepoRepository) UpdateGitRepo(
+	gr *models.GitRepo,
+) (*models.GitRepo, error) {
+	if err := repo.db.Save(gr).Error; err != nil {
+		return nil, err
+	}
+
+	return gr, nil
+}
+
+// DeleteGitRepo removes a git repo from the db
+func (repo *GitRepoRepository) DeleteGitRepo(
+	gr *models.GitRepo,
+) error {
+	if err := repo.db.Where("id = ?", gr.ID).Delete(&models.GitRepo{}).Error; err != nil {
+		return err
+	}
+
+	return nil
+}

+ 40 - 0
internal/repository/gorm/gitrepo_test.go

@@ -91,3 +91,43 @@ func TestListGitReposByProjectID(t *testing.T) {
 		t.Error(diff)
 		t.Error(diff)
 	}
 	}
 }
 }
+
+func TestUpdateGitRepo(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_update_gr.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initGitRepo(tester, t)
+	defer cleanup(tester, t)
+
+	gr := tester.initGRs[0]
+
+	gr.RepoEntity = "porter-dev-new-name"
+
+	gr, err := tester.repo.GitRepo.UpdateGitRepo(
+		gr,
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	gr, err = tester.repo.GitRepo.ReadGitRepo(tester.initGRs[0].ID)
+
+	// make sure data is correct
+	expGR := models.GitRepo{
+		RepoEntity:         "porter-dev-new-name",
+		ProjectID:          tester.initProjects[0].Model.ID,
+		OAuthIntegrationID: tester.initOAuths[0].ID,
+	}
+
+	// reset fields for reflect.DeepEqual
+	gr.Model = orm.Model{}
+
+	if diff := deep.Equal(expGR, *gr); diff != nil {
+		t.Errorf("incorrect git repo")
+		t.Error(diff)
+	}
+}

+ 36 - 0
internal/repository/memory/gitrepo.go

@@ -65,3 +65,39 @@ func (repo *GitRepoRepository) ListGitReposByProjectID(projectID uint) ([]*model
 
 
 	return res, nil
 	return res, nil
 }
 }
+
+// UpdateGitRepo modifies an existing GitRepo in the database
+func (repo *GitRepoRepository) UpdateGitRepo(
+	gr *models.GitRepo,
+) (*models.GitRepo, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot write database")
+	}
+
+	if int(gr.ID-1) >= len(repo.gitRepos) || repo.gitRepos[gr.ID-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	index := int(gr.ID - 1)
+	repo.gitRepos[index] = gr
+
+	return gr, nil
+}
+
+// DeleteGitRepo removes a repoistry from the array by setting it to nil
+func (repo *GitRepoRepository) DeleteGitRepo(
+	gr *models.GitRepo,
+) error {
+	if !repo.canQuery {
+		return errors.New("Cannot write database")
+	}
+
+	if int(gr.ID-1) >= len(repo.gitRepos) || repo.gitRepos[gr.ID-1] == nil {
+		return gorm.ErrRecordNotFound
+	}
+
+	index := int(gr.ID - 1)
+	repo.gitRepos[index] = nil
+
+	return nil
+}

+ 191 - 0
server/api/git_repo_handler.go

@@ -0,0 +1,191 @@
+package api
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	"golang.org/x/oauth2"
+
+	"github.com/go-chi/chi"
+	"github.com/google/go-github/github"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+// HandleListProjectGitRepos returns a list of git repos for a project
+func (app *App) HandleListProjectGitRepos(w http.ResponseWriter, r *http.Request) {
+	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+	if err != nil || projID == 0 {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+
+	grs, err := app.Repo.GitRepo.ListGitReposByProjectID(uint(projID))
+
+	if err != nil {
+		app.handleErrorRead(err, ErrProjectDataRead, w)
+		return
+	}
+
+	extGRs := make([]*models.GitRepoExternal, 0)
+
+	for _, gr := range grs {
+		extGRs = append(extGRs, gr.Externalize())
+	}
+
+	w.WriteHeader(http.StatusOK)
+
+	if err := json.NewEncoder(w).Encode(extGRs); err != nil {
+		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
+		return
+	}
+}
+
+// Repo represents a GitHub or Gitab repository
+type Repo struct {
+	FullName string
+	Kind     string
+}
+
+// DirectoryItem represents a file or subfolder in a repository
+type DirectoryItem struct {
+	Path string
+	Type string
+}
+
+// HandleListRepos retrieves a list of repo names
+func (app *App) HandleListRepos(w http.ResponseWriter, r *http.Request) {
+	tok, err := app.githubTokenFromRequest(r)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	res := make([]Repo, 0)
+
+	client := github.NewClient(app.GithubConf.Client(oauth2.NoContext, tok))
+
+	// list all repositories for specified user
+	repos, _, err := client.Repositories.List(context.Background(), "", nil)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	// TODO -- check if repo has already been appended -- there may be duplicates
+	for _, repo := range repos {
+		res = append(res, Repo{
+			FullName: repo.GetFullName(),
+			Kind:     "github",
+		})
+	}
+
+	json.NewEncoder(w).Encode(res)
+}
+
+// HandleGetBranches retrieves a list of branch names for a specified repo
+func (app *App) HandleGetBranches(w http.ResponseWriter, r *http.Request) {
+	tok, err := app.githubTokenFromRequest(r)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	name := chi.URLParam(r, "name")
+
+	client := github.NewClient(app.GithubConf.Client(oauth2.NoContext, tok))
+
+	// List all branches for a specified repo
+	branches, _, err := client.Repositories.ListBranches(context.Background(), "", name, nil)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	res := []string{}
+	for _, b := range branches {
+		res = append(res, b.GetName())
+	}
+
+	json.NewEncoder(w).Encode(res)
+}
+
+// HandleGetBranchContents retrieves the contents of a specific branch and subdirectory
+func (app *App) HandleGetBranchContents(w http.ResponseWriter, r *http.Request) {
+	tok, err := app.githubTokenFromRequest(r)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	client := github.NewClient(app.GithubConf.Client(oauth2.NoContext, tok))
+
+	queryParams, err := url.ParseQuery(r.URL.RawQuery)
+	if err != nil {
+		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
+		return
+	}
+
+	name := chi.URLParam(r, "name")
+	branch := chi.URLParam(r, "branch")
+
+	repoContentOptions := github.RepositoryContentGetOptions{}
+	repoContentOptions.Ref = branch
+	_, directoryContents, _, err := client.Repositories.GetContents(context.Background(), "", name, queryParams["dir"][0], &repoContentOptions)
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	res := []DirectoryItem{}
+	for i := range directoryContents {
+		d := DirectoryItem{}
+		d.Path = *directoryContents[i].Path
+		d.Type = *directoryContents[i].Type
+		res = append(res, d)
+	}
+
+	// Ret2: recursively traverse all dirs to create config bundle (case on type == dir)
+	// https://api.github.com/repos/porter-dev/porter/contents?ref=frontend-graph
+	// fmt.Println(res)
+	json.NewEncoder(w).Encode(res)
+}
+
+// finds the github token given the git repo id and the project id
+func (app *App) githubTokenFromRequest(
+	r *http.Request,
+) (*oauth2.Token, error) {
+	grID, err := strconv.ParseUint(chi.URLParam(r, "git_repo_id"), 0, 64)
+
+	if err != nil || grID == 0 {
+		return nil, fmt.Errorf("could not read git repo id")
+	}
+
+	// query for the git repo
+	gr, err := app.Repo.GitRepo.ReadGitRepo(uint(grID))
+
+	if err != nil {
+		return nil, err
+	}
+
+	// get the oauth integration
+	oauthInt, err := app.Repo.OAuthIntegration.ReadOAuthIntegration(gr.OAuthIntegrationID)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return &oauth2.Token{
+		AccessToken:  string(oauthInt.AccessToken),
+		RefreshToken: string(oauthInt.RefreshToken),
+		TokenType:    "Bearer",
+	}, nil
+}

+ 0 - 0
server/api/repo_handler_test.go → server/api/git_repo_handler_test.go


+ 191 - 180
server/api/oauth_github_handler.go

@@ -1,182 +1,193 @@
 package api
 package api
 
 
-// import (
-// 	"context"
-// 	"fmt"
-// 	"net/http"
-// 	"strconv"
-
-// 	"github.com/porter-dev/porter/internal/models"
-
-// 	"github.com/go-chi/chi"
-// 	"github.com/google/go-github/github"
-// 	"github.com/porter-dev/porter/internal/oauth"
-// 	"golang.org/x/oauth2"
-// )
-
-// // HandleGithubOAuthStartUser starts the oauth2 flow for a user login request.
-// func (app *App) HandleGithubOAuthStartUser(w http.ResponseWriter, r *http.Request) {
-// 	state := oauth.CreateRandomState()
-
-// 	err := app.populateOAuthSession(w, r, state, false)
-
-// 	if err != nil {
-// 		app.handleErrorDataRead(err, w)
-// 		return
-// 	}
-
-// 	// specify access type offline to get a refresh token
-// 	url := app.GithubConfig.AuthCodeURL(state, oauth2.AccessTypeOnline)
-
-// 	http.Redirect(w, r, url, 302)
-// }
-
-// // HandleGithubOAuthStartProject starts the oauth2 flow for a project repo request.
-// // In this handler, the project id gets written to the session (along with the oauth
-// // state param), so that the correct project id can be identified in the callback.
-// func (app *App) HandleGithubOAuthStartProject(w http.ResponseWriter, r *http.Request) {
-// 	state := oauth.CreateRandomState()
-
-// 	err := app.populateOAuthSession(w, r, state, true)
-
-// 	if err != nil {
-// 		app.handleErrorDataRead(err, w)
-// 		return
-// 	}
-
-// 	// specify access type offline to get a refresh token
-// 	url := app.GithubConfig.AuthCodeURL(state, oauth2.AccessTypeOffline)
-
-// 	http.Redirect(w, r, url, 302)
-// }
-
-// // HandleGithubOAuthCallback verifies the callback request by checking that the
-// // state parameter has not been modified, and validates the token.
-// // There is a difference between the oauth flow when logging a user in, and when
-// // linking a repository.
-// //
-// // When logging a user in, the access token gets stored in the session, and no refresh
-// // token is requested. We store the access token in the session because a user can be
-// // logged in multiple times with a single access token.
-// //
-// // NOTE: this user flow will likely be augmented with Dex, or entirely replaced with Dex.
-// //
-// // However, when linking a repository, the access token and refresh token are requested when
-// // the flow has started. A project also gets linked to the session. After callback, a new
-// // github config gets stored for the project, and the user will then get redirected to
-// // a URL that allows them to select their repositories they'd like to link. We require a refresh
-// // token because we need permanent access to the linked repository.
-// func (app *App) HandleGithubOAuthCallback(w http.ResponseWriter, r *http.Request) {
-// 	session, err := app.store.Get(r, app.cookieName)
-
-// 	if err != nil {
-// 		app.handleErrorDataRead(err, w)
-// 		return
-// 	}
-
-// 	if _, ok := session.Values["state"]; !ok {
-// 		app.sendExternalError(
-// 			err,
-// 			http.StatusForbidden,
-// 			HTTPError{
-// 				Code: http.StatusForbidden,
-// 				Errors: []string{
-// 					"Could not read cookie: are cookies enabled?",
-// 				},
-// 			},
-// 			w,
-// 		)
-
-// 		return
-// 	}
-
-// 	if r.URL.Query().Get("state") != session.Values["state"] {
-// 		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-// 		return
-// 	}
-
-// 	token, err := app.GithubConfig.Exchange(oauth2.NoContext, r.URL.Query().Get("code"))
-
-// 	if err != nil {
-// 		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-// 		return
-// 	}
-
-// 	if !token.Valid() {
-// 		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-// 		return
-// 	}
-
-// 	userID, _ := session.Values["user_id"].(uint)
-// 	projID, _ := session.Values["project_id"].(uint)
-
-// 	app.updateProjectFromToken(projID, userID, token)
-
-// 	if session.Values["query_params"] != "" {
-// 		http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", session.Values["query_params"]), 302)
-// 	} else {
-// 		http.Redirect(w, r, "/dashboard", 302)
-// 	}
-// }
-
-// func (app *App) populateOAuthSession(w http.ResponseWriter, r *http.Request, state string, isProject bool) error {
-// 	session, err := app.store.Get(r, app.cookieName)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	// need state parameter to validate when redirected
-// 	session.Values["state"] = state
-
-// 	if isProject {
-// 		// read the project id and add it to the session
-// 		projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-// 		if err != nil || projID == 0 {
-// 			return fmt.Errorf("could not read project id")
-// 		}
-
-// 		session.Values["project_id"] = projID
-// 		session.Values["query_params"] = r.URL.RawQuery
-// 	}
-
-// 	if err := session.Save(r, w); err != nil {
-// 		app.logger.Warn().Err(err)
-// 	}
-
-// 	return nil
-// }
-
-// func (app *App) upsertUserFromToken() error {
-// 	return fmt.Errorf("UNIMPLEMENTED")
-// }
-
-// // updates a project's repository clients with the token information.
-// func (app *App) updateProjectFromToken(projectID uint, userID uint, tok *oauth2.Token) error {
-// 	// get the list of repositories that this token has access to
-// 	client := github.NewClient(app.GithubConfig.Client(oauth2.NoContext, tok))
-
-// 	user, _, err := client.Users.Get(context.Background(), "")
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	repoClient := &models.RepoClient{
-// 		ProjectID:    projectID,
-// 		UserID:       userID,
-// 		RepoUserID:   uint(user.GetID()),
-// 		Kind:         models.RepoClientGithub,
-// 		AccessToken:  []byte(tok.AccessToken),
-// 		RefreshToken: []byte(tok.RefreshToken),
-// 	}
-
-// 	repoClient, err = app.repo.RepoClient.CreateRepoClient(repoClient)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	return nil
-// }
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strconv"
+
+	"github.com/porter-dev/porter/internal/models"
+
+	"github.com/go-chi/chi"
+	"github.com/google/go-github/github"
+	"github.com/porter-dev/porter/internal/oauth"
+	"golang.org/x/oauth2"
+
+	"github.com/porter-dev/porter/internal/models/integrations"
+)
+
+// HandleGithubOAuthStartUser starts the oauth2 flow for a user login request.
+func (app *App) HandleGithubOAuthStartUser(w http.ResponseWriter, r *http.Request) {
+	state := oauth.CreateRandomState()
+
+	err := app.populateOAuthSession(w, r, state, false)
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// specify access type offline to get a refresh token
+	url := app.GithubConf.AuthCodeURL(state, oauth2.AccessTypeOnline)
+
+	http.Redirect(w, r, url, 302)
+}
+
+// HandleGithubOAuthStartProject starts the oauth2 flow for a project repo request.
+// In this handler, the project id gets written to the session (along with the oauth
+// state param), so that the correct project id can be identified in the callback.
+func (app *App) HandleGithubOAuthStartProject(w http.ResponseWriter, r *http.Request) {
+	state := oauth.CreateRandomState()
+
+	err := app.populateOAuthSession(w, r, state, true)
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	// specify access type offline to get a refresh token
+	url := app.GithubConf.AuthCodeURL(state, oauth2.AccessTypeOffline)
+
+	http.Redirect(w, r, url, 302)
+}
+
+// HandleGithubOAuthCallback verifies the callback request by checking that the
+// state parameter has not been modified, and validates the token.
+// There is a difference between the oauth flow when logging a user in, and when
+// linking a repository.
+//
+// When logging a user in, the access token gets stored in the session, and no refresh
+// token is requested. We store the access token in the session because a user can be
+// logged in multiple times with a single access token.
+//
+// NOTE: this user flow will likely be augmented with Dex, or entirely replaced with Dex.
+//
+// However, when linking a repository, the access token and refresh token are requested when
+// the flow has started. A project also gets linked to the session. After callback, a new
+// github config gets stored for the project, and the user will then get redirected to
+// a URL that allows them to select their repositories they'd like to link. We require a refresh
+// token because we need permanent access to the linked repository.
+func (app *App) HandleGithubOAuthCallback(w http.ResponseWriter, r *http.Request) {
+	session, err := app.Store.Get(r, app.ServerConf.CookieName)
+
+	if err != nil {
+		app.handleErrorDataRead(err, w)
+		return
+	}
+
+	if _, ok := session.Values["state"]; !ok {
+		app.sendExternalError(
+			err,
+			http.StatusForbidden,
+			HTTPError{
+				Code: http.StatusForbidden,
+				Errors: []string{
+					"Could not read cookie: are cookies enabled?",
+				},
+			},
+			w,
+		)
+
+		return
+	}
+
+	if r.URL.Query().Get("state") != session.Values["state"] {
+		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		return
+	}
+
+	token, err := app.GithubConf.Exchange(oauth2.NoContext, r.URL.Query().Get("code"))
+
+	if err != nil {
+		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		return
+	}
+
+	if !token.Valid() {
+		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		return
+	}
+
+	userID, _ := session.Values["user_id"].(uint)
+	projID, _ := session.Values["project_id"].(uint)
+
+	app.updateProjectFromToken(projID, userID, token)
+
+	if session.Values["query_params"] != "" {
+		http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", session.Values["query_params"]), 302)
+	} else {
+		http.Redirect(w, r, "/dashboard", 302)
+	}
+}
+
+func (app *App) populateOAuthSession(w http.ResponseWriter, r *http.Request, state string, isProject bool) error {
+	session, err := app.Store.Get(r, app.ServerConf.CookieName)
+
+	if err != nil {
+		return err
+	}
+
+	// need state parameter to validate when redirected
+	session.Values["state"] = state
+
+	if isProject {
+		// read the project id and add it to the session
+		projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
+
+		if err != nil || projID == 0 {
+			return fmt.Errorf("could not read project id")
+		}
+
+		session.Values["project_id"] = projID
+		session.Values["query_params"] = r.URL.RawQuery
+	}
+
+	if err := session.Save(r, w); err != nil {
+		app.Logger.Warn().Err(err)
+	}
+
+	return nil
+}
+
+func (app *App) upsertUserFromToken() error {
+	return fmt.Errorf("UNIMPLEMENTED")
+}
+
+// updates a project's repository clients with the token information.
+func (app *App) updateProjectFromToken(projectID uint, userID uint, tok *oauth2.Token) error {
+	// get the list of repositories that this token has access to
+	client := github.NewClient(app.GithubConf.Client(oauth2.NoContext, tok))
+
+	user, _, err := client.Users.Get(context.Background(), "")
+
+	if err != nil {
+		return err
+	}
+
+	oauthInt := &integrations.OAuthIntegration{
+		Client:       integrations.OAuthGithub,
+		UserID:       userID,
+		ProjectID:    projectID,
+		AccessToken:  []byte(tok.AccessToken),
+		RefreshToken: []byte(tok.RefreshToken),
+	}
+
+	// create the oauth integration first
+	oauthInt, err = app.Repo.OAuthIntegration.CreateOAuthIntegration(oauthInt)
+
+	if err != nil {
+		return err
+	}
+
+	// create the git repo
+	gr := &models.GitRepo{
+		ProjectID:          projectID,
+		RepoEntity:         *user.Name,
+		OAuthIntegrationID: oauthInt.ID,
+	}
+
+	gr, err = app.Repo.GitRepo.CreateGitRepo(gr)
+
+	return err
+}

+ 0 - 175
server/api/repo_handler.go

@@ -1,175 +0,0 @@
-package api
-
-// import (
-// 	"context"
-// 	"encoding/json"
-// 	"fmt"
-// 	"net/http"
-// 	"net/url"
-// 	"strconv"
-
-// 	"golang.org/x/oauth2"
-
-// 	"github.com/go-chi/chi"
-// 	"github.com/google/go-github/v32/github"
-// )
-
-// // Repo represents a GitHub or Gitab repository
-// type Repo struct {
-// 	FullName string
-// 	Kind     string
-// }
-
-// // DirectoryItem represents a file or subfolder in a repository
-// type DirectoryItem struct {
-// 	Path string
-// 	Type string
-// }
-
-// // HandleListRepos retrieves a list of repo names
-// func (app *App) HandleListRepos(w http.ResponseWriter, r *http.Request) {
-// 	tok, err := app.githubTokenFromRequest(r)
-
-// 	if err != nil {
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	res := make([]Repo, 0)
-
-// 	client := github.NewClient(app.GithubConfig.Client(oauth2.NoContext, tok))
-
-// 	// list all repositories for specified user
-// 	repos, _, err := client.Repositories.List(context.Background(), "", nil)
-
-// 	if err != nil {
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	// TODO -- check if repo has already been appended -- there may be duplicates
-// 	for _, repo := range repos {
-// 		res = append(res, Repo{
-// 			FullName: repo.GetFullName(),
-// 			Kind:     "github",
-// 		})
-// 	}
-
-// 	json.NewEncoder(w).Encode(res)
-// }
-
-// // HandleGetBranches retrieves a list of branch names for a specified repo
-// func (app *App) HandleGetBranches(w http.ResponseWriter, r *http.Request) {
-// 	tok, err := app.githubTokenFromRequest(r)
-
-// 	if err != nil {
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	name := chi.URLParam(r, "name")
-
-// 	client := github.NewClient(app.GithubConfig.Client(oauth2.NoContext, tok))
-
-// 	// List all branches for a specified repo
-// 	branches, _, err := client.Repositories.ListBranches(context.Background(), "", name, nil)
-// 	if err != nil {
-// 		fmt.Println(err)
-// 		return
-// 	}
-
-// 	res := []string{}
-// 	for _, b := range branches {
-// 		res = append(res, b.GetName())
-// 	}
-
-// 	json.NewEncoder(w).Encode(res)
-// }
-
-// // HandleGetBranchContents retrieves the contents of a specific branch and subdirectory
-// func (app *App) HandleGetBranchContents(w http.ResponseWriter, r *http.Request) {
-// 	tok, err := app.githubTokenFromRequest(r)
-
-// 	if err != nil {
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	client := github.NewClient(app.GithubConfig.Client(oauth2.NoContext, tok))
-
-// 	queryParams, err := url.ParseQuery(r.URL.RawQuery)
-// 	if err != nil {
-// 		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
-// 		return
-// 	}
-
-// 	name := chi.URLParam(r, "name")
-// 	branch := chi.URLParam(r, "branch")
-
-// 	repoContentOptions := github.RepositoryContentGetOptions{}
-// 	repoContentOptions.Ref = branch
-// 	_, directoryContents, _, err := client.Repositories.GetContents(context.Background(), "", name, queryParams["dir"][0], &repoContentOptions)
-// 	if err != nil {
-// 		app.handleErrorInternal(err, w)
-// 		return
-// 	}
-
-// 	res := []DirectoryItem{}
-// 	for i := range directoryContents {
-// 		d := DirectoryItem{}
-// 		d.Path = *directoryContents[i].Path
-// 		d.Type = *directoryContents[i].Type
-// 		res = append(res, d)
-// 	}
-
-// 	// Ret2: recursively traverse all dirs to create config bundle (case on type == dir)
-// 	// https://api.github.com/repos/porter-dev/porter/contents?ref=frontend-graph
-// 	// fmt.Println(res)
-// 	json.NewEncoder(w).Encode(res)
-// }
-
-// func (app *App) githubTokenFromRequest(
-// 	r *http.Request,
-// ) (*oauth2.Token, error) {
-// 	// read project id
-// 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-// 	if err != nil || projID == 0 {
-// 		return nil, fmt.Errorf("could not read project id")
-// 	}
-
-// 	// read user id
-// 	session, err := app.store.Get(r, app.cookieName)
-
-// 	if err != nil {
-// 		return nil, fmt.Errorf("could not read user id")
-// 	}
-
-// 	userID, ok := session.Values["user_id"].(uint)
-
-// 	if !ok {
-// 		return nil, fmt.Errorf("could not read user id")
-// 	}
-
-// 	// query for repo client
-// 	gitRepos, err := app.repo.GitRepo.ListGitReposByProjectID(uint(projID))
-
-// 	if err != nil {
-// 		return nil, err
-// 	}
-
-// 	for _, rc := range repoClients {
-// 		// find the RepoClient that matches the user id in the request
-// 		if rc.UserID == userID {
-// 			// TODO -- refresh token is irrelevant at the moment, because the access token
-// 			// doesn't expire.
-// 			return &oauth2.Token{
-// 				AccessToken:  string(rc.AccessToken),
-// 				RefreshToken: string(rc.RefreshToken),
-// 				TokenType:    "Bearer",
-// 			}, nil
-// 		}
-// 	}
-
-// 	return nil, fmt.Errorf("could not find matching token")
-// }