Bläddra i källkod

Merge pull request #2788 from porter-dev/default-add-support

auto-add admin after cc
jusrhee 3 år sedan
förälder
incheckning
3fcc804d69

+ 60 - 0
api/server/handlers/project/invite_admin.go

@@ -0,0 +1,60 @@
+package project
+
+import (
+	"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/config"
+	"github.com/porter-dev/porter/api/server/shared/config/envloader"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+)
+
+type ProjectInviteAdminHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewProjectInviteAdminHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *ProjectInviteAdminHandler {
+	return &ProjectInviteAdminHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (p *ProjectInviteAdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+
+	// Only add admin user if config is set
+	InstanceEnvConf, _ := envloader.FromEnv()
+	adminUserId := InstanceEnvConf.ServerConf.AdminUserId
+	if adminUserId == 0 {
+		return
+	}
+
+	request := &types.ProjectInviteAdminRequest{}
+	ok := p.DecodeAndValidate(w, r, request)
+	if !ok {
+		return
+	}
+
+	// Read the user and project from context
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	// Create role for admin if it doesn't exist
+	projectRepo := p.Repo().Project()
+	role, _ := projectRepo.ReadProjectRole(proj.ID, adminUserId)
+	if role == nil {
+		projectRepo.CreateProjectRole(proj, &models.Role{
+			Role: types.Role{
+				UserID:    adminUserId,
+				ProjectID: proj.ID,
+				Kind:      types.RoleAdmin,
+			},
+		})
+	}
+
+	p.WriteResult(w, r, proj.ToProjectType())
+}

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

@@ -201,6 +201,31 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
+	// POST /api/projects/{project_id}/invite_admin -> project.NewProjectInviteAdminHandler
+	projectInviteAdminEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/invite_admin",
+			},
+			Scopes: []types.PermissionScope{types.ProjectScope},
+		},
+	)
+
+	projectInviteAdminHandler := project.NewProjectInviteAdminHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: projectInviteAdminEndpoint,
+		Handler:  projectInviteAdminHandler,
+		Router:   r,
+	})
+
 	// GET /api/projects/{project_id}/usage -> project.NewProjectGetUsageHandler
 	getUsageEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 2 - 1
api/server/shared/config/env/envconfs.go

@@ -88,7 +88,8 @@ type ServerConf struct {
 	// Email for an admin user. On a self-hosted instance of Porter, the
 	// admin user is the only user that can log in and register. After the admin
 	// user has logged in, registration is turned off.
-	AdminEmail string `env:"ADMIN_EMAIL"`
+	AdminEmail  string `env:"ADMIN_EMAIL"`
+	AdminUserId uint   `env:"ADMIN_USER_ID"`
 
 	SentryDSN string `env:"SENTRY_DSN"`
 	SentryEnv string `env:"SENTRY_ENV,default=dev"`

+ 2 - 0
api/types/project.go

@@ -31,6 +31,8 @@ type CreateProjectRoleRequest struct {
 	UserID uint   `json:"user_id" form:"required"`
 }
 
+type ProjectInviteAdminRequest struct{}
+
 type ReadProjectResponse Project
 
 type ListProjectsRequest struct{}

+ 10 - 1
dashboard/src/components/ProvisionerFlow.tsx

@@ -24,7 +24,7 @@ type Props = {
 
 const ProvisionerFlow: React.FC<Props> = ({
 }) => {
-  const { usage, hasBillingEnabled } = useContext(Context);
+  const { usage, hasBillingEnabled, currentProject } = useContext(Context);
   const [currentStep, setCurrentStep] = useState("cloud");
   const [credentialId, setCredentialId] = useState("");
   const [showCostConfirmModal, setShowCostConfirmModal] = useState(false);
@@ -47,6 +47,15 @@ const ProvisionerFlow: React.FC<Props> = ({
     } catch (err) {
       console.log(err);
     }
+    try {
+      const res = await api.inviteAdmin(
+        "<token>", 
+        {}, 
+        { project_id: currentProject.id }
+      );
+    } catch (err) {
+      console.log(err);
+    }
   }
 
   if (currentStep === "cloud") {

+ 8 - 0
dashboard/src/shared/api.tsx

@@ -317,6 +317,13 @@ const createInvite = baseApi<
   return `/api/projects/${pathParams.id}/invites`;
 });
 
+const inviteAdmin = baseApi<
+  {},
+  { project_id: number }
+>("POST", (pathParams) => {
+  return `/api/projects/${pathParams.project_id}/invite_admin`;
+});
+
 const createPasswordReset = baseApi<
   {
     email: string;
@@ -2549,6 +2556,7 @@ export default {
   getChartsFromHelmRepo,
   getChartInfoFromHelmRepo,
   linkGithubProject,
+  inviteAdmin,
   getGithubAccounts,
   listConfigMaps,
   logInUser,