Jelajahi Sumber

Added can create project endpoint

jnfrati 4 tahun lalu
induk
melakukan
43facbf7c0

+ 47 - 0
api/server/handlers/user/can_create_project.go

@@ -0,0 +1,47 @@
+package user
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type CanCreateProject struct {
+	handlers.PorterHandlerWriter
+}
+
+func NewCanCreateProjectHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *CanCreateProject {
+	return &CanCreateProject{
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *CanCreateProject) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	user, _ := r.Context().Value(types.UserScope).(*models.User)
+
+	exists, err := c.Repo().Allowlist().UserEmailExists(user.Email)
+
+	if err != nil {
+		err = fmt.Errorf("couldn't retrieve user: %s", err.Error())
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	if !exists {
+		err = fmt.Errorf("user is not authorized")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, 403))
+		return
+	}
+
+	c.WriteResult(w, r, user.ToUserType())
+}

+ 25 - 0
api/server/router/user.go

@@ -421,5 +421,30 @@ func getUserRoutes(
 		Router:   r,
 	})
 
+	// GET /api/can_create_project -> user.CanCreateProject
+	canCreateProjectEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: "/can_create_project",
+			},
+			Scopes: []types.PermissionScope{types.UserScope},
+		},
+	)
+
+	canCreateProjectHandler := user.NewCanCreateProjectHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: canCreateProjectEndpoint,
+		Handler:  canCreateProjectHandler,
+		Router:   r,
+	})
+
 	return routes
 }

+ 12 - 0
internal/models/allowlist.go

@@ -0,0 +1,12 @@
+package models
+
+import (
+	"gorm.io/gorm"
+)
+
+// Allowlist is a simple list with all the users emails allowed to create new projects
+type Allowlist struct {
+	gorm.Model
+
+	UserEmail string `json:"user_email" gorm:"unique;not null"`
+}

+ 7 - 0
internal/repository/allowlist.go

@@ -0,0 +1,7 @@
+package repository
+
+// AllowlistRepository represents the set of queries on the
+// Allowlist model
+type AllowlistRepository interface {
+	UserEmailExists(email string) (bool, error)
+}

+ 33 - 0
internal/repository/gorm/allowlist.go

@@ -0,0 +1,33 @@
+package gorm
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// AllowlistRepository uses gorm.DB for querying the database
+type AllowlistRepository struct {
+	db *gorm.DB
+}
+
+// NewAllowlistRepository returns a AllowListRepository which uses
+// gorm.DB for querying the database.
+func NewAllowlistRepository(db *gorm.DB) repository.AllowlistRepository {
+	return &AllowlistRepository{db}
+}
+
+func (repo *AllowlistRepository) UserEmailExists(email string) (bool, error) {
+	al := &models.Allowlist{}
+	result := repo.db.Where("user_email = ?", email).Find(&al)
+
+	if err := result.Error; err != nil {
+		return false, err
+	}
+
+	if result.RowsAffected > 0 {
+		return true, nil
+	}
+
+	return false, nil
+}

+ 1 - 0
internal/repository/gorm/migrate.go

@@ -36,6 +36,7 @@ func AutoMigrate(db *gorm.DB) error {
 		&models.Onboarding{},
 		&models.CredentialsExchangeToken{},
 		&models.BuildConfig{},
+		&models.Allowlist{},
 		&ints.KubeIntegration{},
 		&ints.BasicIntegration{},
 		&ints.OIDCIntegration{},

+ 6 - 0
internal/repository/gorm/repository.go

@@ -37,6 +37,7 @@ type GormRepository struct {
 	onboarding                repository.ProjectOnboardingRepository
 	ceToken                   repository.CredentialsExchangeTokenRepository
 	buildConfig               repository.BuildConfigRepository
+	allowlist                 repository.AllowlistRepository
 }
 
 func (t *GormRepository) User() repository.UserRepository {
@@ -159,6 +160,10 @@ func (t *GormRepository) BuildConfig() repository.BuildConfigRepository {
 	return t.buildConfig
 }
 
+func (t *GormRepository) Allowlist() repository.AllowlistRepository {
+	return t.allowlist
+}
+
 // NewRepository returns a Repository which persists users in memory
 // and accepts a parameter that can trigger read/write errors
 func NewRepository(db *gorm.DB, key *[32]byte, storageBackend credentials.CredentialStorage) repository.Repository {
@@ -193,5 +198,6 @@ func NewRepository(db *gorm.DB, key *[32]byte, storageBackend credentials.Creden
 		onboarding:                NewProjectOnboardingRepository(db),
 		ceToken:                   NewCredentialsExchangeTokenRepository(db),
 		buildConfig:               NewBuildConfigRepository(db),
+		allowlist:                 NewAllowlistRepository(db),
 	}
 }

+ 1 - 0
internal/repository/repository.go

@@ -31,4 +31,5 @@ type Repository interface {
 	Onboarding() ProjectOnboardingRepository
 	CredentialsExchangeToken() CredentialsExchangeTokenRepository
 	BuildConfig() BuildConfigRepository
+	Allowlist() AllowlistRepository
 }

+ 5 - 0
internal/repository/test/repository.go

@@ -35,6 +35,7 @@ type TestRepository struct {
 	onboarding                repository.ProjectOnboardingRepository
 	ceToken                   repository.CredentialsExchangeTokenRepository
 	buildConfig               repository.BuildConfigRepository
+	allowlist                 repository.AllowlistRepository
 }
 
 func (t *TestRepository) User() repository.UserRepository {
@@ -157,6 +158,10 @@ func (t *TestRepository) BuildConfig() repository.BuildConfigRepository {
 	return t.buildConfig
 }
 
+func (t *TestRepository) Allowlist() repository.AllowlistRepository {
+	return t.allowlist
+}
+
 // NewRepository returns a Repository which persists users in memory
 // and accepts a parameter that can trigger read/write errors
 func NewRepository(canQuery bool, failingMethods ...string) repository.Repository {