diff --git a/app/cli/cmd/organization.go b/app/cli/cmd/organization.go index 10c4b56cd..c3b076e6b 100644 --- a/app/cli/cmd/organization.go +++ b/app/cli/cmd/organization.go @@ -26,6 +26,11 @@ func newOrganizationCmd() *cobra.Command { Short: "Organizations management", } - cmd.AddCommand(newOrganizationList(), newOrganizationSet(), newOrganizationDescribeCmd()) + cmd.AddCommand( + newOrganizationList(), + newOrganizationSet(), + newOrganizationDescribeCmd(), + newOrganizationInvitationCmd(), + ) return cmd } diff --git a/app/cli/cmd/organization_describe.go b/app/cli/cmd/organization_describe.go index cdf9e31a9..b29813e0d 100644 --- a/app/cli/cmd/organization_describe.go +++ b/app/cli/cmd/organization_describe.go @@ -46,7 +46,7 @@ func contextTableOutput(config *action.ConfigContextItem) error { gt.SetTitle("Current Context") gt.AppendRow(table.Row{"Logged in as", config.CurrentUser.Email}) gt.AppendSeparator() - gt.AppendRow(table.Row{"Organization", config.CurrentOrg.Name}) + gt.AppendRow(table.Row{"Organization", fmt.Sprintf("%s (%s)", config.CurrentOrg.Name, config.CurrentOrg.ID)}) backend := config.CurrentCASBackend if backend != nil { gt.AppendSeparator() diff --git a/app/cli/cmd/organization_invitation.go b/app/cli/cmd/organization_invitation.go new file mode 100644 index 000000000..b08aeef2b --- /dev/null +++ b/app/cli/cmd/organization_invitation.go @@ -0,0 +1,32 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "github.com/spf13/cobra" +) + +func newOrganizationInvitationCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "invitation", + Aliases: []string{"invite"}, + Short: "User Invitations", + } + + cmd.AddCommand(newOrganizationInvitationListSentCmd(), newOrganizationInvitationCreateCmd(), newOrganizationInvitationRevokeCmd()) + + return cmd +} diff --git a/app/cli/cmd/organization_invitation_create.go b/app/cli/cmd/organization_invitation_create.go new file mode 100644 index 000000000..7379dbe95 --- /dev/null +++ b/app/cli/cmd/organization_invitation_create.go @@ -0,0 +1,50 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + + "github.com/chainloop-dev/chainloop/app/cli/internal/action" + "github.com/spf13/cobra" +) + +func newOrganizationInvitationCreateCmd() *cobra.Command { + var receiverEmail, organizationID string + cmd := &cobra.Command{ + Use: "create", + Short: "Invite a User to an Organization", + RunE: func(cmd *cobra.Command, args []string) error { + res, err := action.NewOrgInvitationCreate(actionOpts).Run( + context.Background(), organizationID, receiverEmail) + if err != nil { + return err + } + + return encodeOutput([]*action.OrgInvitationItem{res}, orgInvitationTableOutput) + }, + } + + cmd.Flags().StringVar(&receiverEmail, "receiver", "", "Email of the user to invite") + err := cmd.MarkFlagRequired("receiver") + cobra.CheckErr(err) + + cmd.Flags().StringVar(&organizationID, "organization", "", "ID of the organization to invite the user to") + err = cmd.MarkFlagRequired("organization") + cobra.CheckErr(err) + + return cmd +} diff --git a/app/cli/cmd/organization_invitation_list_sent.go b/app/cli/cmd/organization_invitation_list_sent.go new file mode 100644 index 000000000..a69fb353e --- /dev/null +++ b/app/cli/cmd/organization_invitation_list_sent.go @@ -0,0 +1,62 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + "fmt" + "time" + + "github.com/chainloop-dev/chainloop/app/cli/internal/action" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" +) + +func newOrganizationInvitationListSentCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + Short: "List sent invitations", + RunE: func(cmd *cobra.Command, args []string) error { + res, err := action.NewOrgInvitationListSent(actionOpts).Run(context.Background()) + if err != nil { + return err + } + + return encodeOutput(res, orgInvitationTableOutput) + }, + } + + return cmd +} + +func orgInvitationTableOutput(items []*action.OrgInvitationItem) error { + if len(items) == 0 { + fmt.Println("there are no sent invitations") + return nil + } + + t := newTableWriter() + t.AppendHeader(table.Row{"ID", "Org Name", "Receiver Email", "Status", "Created At"}) + + for _, i := range items { + t.AppendRow(table.Row{i.ID, i.Organization.Name, i.ReceiverEmail, i.Status, i.CreatedAt.Format(time.RFC822)}) + t.AppendSeparator() + } + + t.Render() + return nil +} diff --git a/app/cli/cmd/organization_invitation_revoke.go b/app/cli/cmd/organization_invitation_revoke.go new file mode 100644 index 000000000..b917c6a3e --- /dev/null +++ b/app/cli/cmd/organization_invitation_revoke.go @@ -0,0 +1,45 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + + "github.com/chainloop-dev/chainloop/app/cli/internal/action" + "github.com/spf13/cobra" +) + +func newOrganizationInvitationRevokeCmd() *cobra.Command { + var invitationID string + cmd := &cobra.Command{ + Use: "revoke", + Short: "Revoke a pending invitation", + RunE: func(cmd *cobra.Command, args []string) error { + if err := action.NewOrgInvitationRevoke(actionOpts).Run(context.Background(), invitationID); err != nil { + return err + } + + logger.Info().Msg("Invitation Revoked!") + return nil + }, + } + + cmd.Flags().StringVar(&invitationID, "id", "", "Invitation ID") + err := cmd.MarkFlagRequired("id") + cobra.CheckErr(err) + + return cmd +} diff --git a/app/cli/cmd/organization_list.go b/app/cli/cmd/organization_list.go index dd80412cc..3742898be 100644 --- a/app/cli/cmd/organization_list.go +++ b/app/cli/cmd/organization_list.go @@ -49,10 +49,10 @@ func orgMembershipTableOutput(items []*action.MembershipItem) error { } t := newTableWriter() - t.AppendHeader(table.Row{"ID", "Org Name", "Current", "Joined At"}) + t.AppendHeader(table.Row{"Org ID", "Org Name", "Current", "Joined At"}) for _, i := range items { - t.AppendRow(table.Row{i.ID, i.Org.Name, i.Current, i.CreatedAt.Format(time.RFC822)}) + t.AppendRow(table.Row{i.Org.ID, i.Org.Name, i.Current, i.CreatedAt.Format(time.RFC822)}) t.AppendSeparator() } diff --git a/app/cli/cmd/organization_set.go b/app/cli/cmd/organization_set.go index 72a88182c..ea56633c9 100644 --- a/app/cli/cmd/organization_set.go +++ b/app/cli/cmd/organization_set.go @@ -16,28 +16,48 @@ package cmd import ( + "fmt" + "github.com/chainloop-dev/chainloop/app/cli/internal/action" "github.com/spf13/cobra" ) func newOrganizationSet() *cobra.Command { - var membershipID string + var orgID string cmd := &cobra.Command{ Use: "set", Short: "Set the current organization associated with this user", RunE: func(cmd *cobra.Command, args []string) error { - res, err := action.NewMembershipSet(actionOpts).Run(membershipID) + // To change the current organization, we need to find the membership ID + memberships, err := action.NewMembershipList(actionOpts).Run() + if err != nil { + return err + } + + var membershipID string + for _, m := range memberships { + if m.Org.ID == orgID { + membershipID = m.ID + break + } + } + + if membershipID == "" { + return fmt.Errorf("organization %s not found", orgID) + } + + m, err := action.NewMembershipSet(actionOpts).Run(membershipID) if err != nil { return err } logger.Info().Msg("Organization switched!") - return encodeOutput([]*action.MembershipItem{res}, orgMembershipTableOutput) + return encodeOutput([]*action.MembershipItem{m}, orgMembershipTableOutput) }, } - cmd.Flags().StringVar(&membershipID, "id", "", "membership ID to make the switch") + cmd.Flags().StringVar(&orgID, "id", "", "organization ID to make the switch") cobra.CheckErr(cmd.MarkFlagRequired("id")) return cmd diff --git a/app/cli/cmd/output.go b/app/cli/cmd/output.go index 2fbcbf7e5..cc6101ed3 100644 --- a/app/cli/cmd/output.go +++ b/app/cli/cmd/output.go @@ -43,7 +43,8 @@ type tabulatedData interface { []*action.AvailableIntegrationItem | []*action.AttachedIntegrationItem | []*action.MembershipItem | - []*action.CASBackendItem + []*action.CASBackendItem | + []*action.OrgInvitationItem } var ErrOutputFormatNotImplemented = errors.New("format not implemented") diff --git a/app/cli/internal/action/config_current_context.go b/app/cli/internal/action/config_current_context.go index b07e51d4f..c6fb235a3 100644 --- a/app/cli/internal/action/config_current_context.go +++ b/app/cli/internal/action/config_current_context.go @@ -31,12 +31,12 @@ func NewConfigCurrentContext(cfg *ActionsOpts) *ConfigCurrentContext { } type ConfigContextItem struct { - CurrentUser *ConfigContextItemUser + CurrentUser *UserItem CurrentOrg *OrgItem CurrentCASBackend *CASBackendItem } -type ConfigContextItemUser struct { +type UserItem struct { ID, Email string CreatedAt *time.Time } @@ -51,12 +51,20 @@ func (action *ConfigCurrentContext) Run() (*ConfigContextItem, error) { res := resp.GetResult() return &ConfigContextItem{ - CurrentUser: &ConfigContextItemUser{ - ID: res.GetCurrentUser().Id, - Email: res.GetCurrentUser().Email, - CreatedAt: toTimePtr(res.GetCurrentUser().CreatedAt.AsTime()), - }, + CurrentUser: pbUserItemToAction(res.GetCurrentUser()), CurrentOrg: pbOrgItemToAction(res.GetCurrentOrg()), CurrentCASBackend: pbCASBackendItemToAction(res.GetCurrentCasBackend()), }, nil } + +func pbUserItemToAction(in *pb.User) *UserItem { + if in == nil { + return nil + } + + return &UserItem{ + ID: in.Id, + Email: in.Email, + CreatedAt: toTimePtr(in.CreatedAt.AsTime()), + } +} diff --git a/app/cli/internal/action/org_invitation_create.go b/app/cli/internal/action/org_invitation_create.go new file mode 100644 index 000000000..4474259f4 --- /dev/null +++ b/app/cli/internal/action/org_invitation_create.go @@ -0,0 +1,44 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package action + +import ( + "context" + + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" +) + +type OrgInvitationCreate struct { + cfg *ActionsOpts +} + +func NewOrgInvitationCreate(cfg *ActionsOpts) *OrgInvitationCreate { + return &OrgInvitationCreate{cfg} +} + +func (action *OrgInvitationCreate) Run(ctx context.Context, organization, receiver string) (*OrgInvitationItem, error) { + client := pb.NewOrgInvitationServiceClient(action.cfg.CPConnection) + resp, err := client.Create(ctx, &pb.OrgInvitationServiceCreateRequest{ + OrganizationId: organization, + ReceiverEmail: receiver, + }) + + if err != nil { + return nil, err + } + + return pbOrgInvitationItemToAction(resp.Result), nil +} diff --git a/app/cli/internal/action/org_invitation_list_sent.go b/app/cli/internal/action/org_invitation_list_sent.go new file mode 100644 index 000000000..930470507 --- /dev/null +++ b/app/cli/internal/action/org_invitation_list_sent.go @@ -0,0 +1,70 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package action + +import ( + "context" + "time" + + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" +) + +type OrgInvitationListSent struct { + cfg *ActionsOpts +} + +type OrgInvitationItem struct { + ID string `json:"id"` + ReceiverEmail string `json:"receiverEmail"` + Organization *OrgItem `json:"organization"` + Sender *UserItem `json:"sender"` + Status string `json:"status"` + CreatedAt *time.Time `json:"createdAt"` +} + +func NewOrgInvitationListSent(cfg *ActionsOpts) *OrgInvitationListSent { + return &OrgInvitationListSent{cfg} +} + +func (action *OrgInvitationListSent) Run(ctx context.Context) ([]*OrgInvitationItem, error) { + client := pb.NewOrgInvitationServiceClient(action.cfg.CPConnection) + resp, err := client.ListSent(ctx, &pb.OrgInvitationServiceListSentRequest{}) + if err != nil { + return nil, err + } + + result := make([]*OrgInvitationItem, 0, len(resp.Result)) + for _, p := range resp.Result { + result = append(result, pbOrgInvitationItemToAction(p)) + } + + return result, nil +} + +func pbOrgInvitationItemToAction(in *pb.OrgInvitationItem) *OrgInvitationItem { + if in == nil { + return nil + } + + return &OrgInvitationItem{ + ID: in.Id, + ReceiverEmail: in.ReceiverEmail, + Organization: pbOrgItemToAction(in.Organization), + Sender: pbUserItemToAction(in.Sender), + CreatedAt: toTimePtr(in.CreatedAt.AsTime()), + Status: in.Status, + } +} diff --git a/app/cli/internal/action/org_invitation_revoke.go b/app/cli/internal/action/org_invitation_revoke.go new file mode 100644 index 000000000..0199f0e7c --- /dev/null +++ b/app/cli/internal/action/org_invitation_revoke.go @@ -0,0 +1,40 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package action + +import ( + "context" + + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" +) + +type OrgInvitationRevoke struct { + cfg *ActionsOpts +} + +func NewOrgInvitationRevoke(cfg *ActionsOpts) *OrgInvitationRevoke { + return &OrgInvitationRevoke{cfg} +} + +func (action *OrgInvitationRevoke) Run(ctx context.Context, invitationID string) error { + client := pb.NewOrgInvitationServiceClient(action.cfg.CPConnection) + _, err := client.Revoke(ctx, &pb.OrgInvitationServiceRevokeRequest{Id: invitationID}) + if err != nil { + return err + } + + return nil +} diff --git a/app/controlplane/api/controlplane/v1/org_invitation.pb.go b/app/controlplane/api/controlplane/v1/org_invitation.pb.go new file mode 100644 index 000000000..6e8a5f97f --- /dev/null +++ b/app/controlplane/api/controlplane/v1/org_invitation.pb.go @@ -0,0 +1,643 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: controlplane/v1/org_invitation.proto + +package v1 + +import ( + _ "github.com/envoyproxy/protoc-gen-validate/validate" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type OrgInvitationServiceCreateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrganizationId string `protobuf:"bytes,1,opt,name=organization_id,json=organizationId,proto3" json:"organization_id,omitempty"` + ReceiverEmail string `protobuf:"bytes,2,opt,name=receiver_email,json=receiverEmail,proto3" json:"receiver_email,omitempty"` +} + +func (x *OrgInvitationServiceCreateRequest) Reset() { + *x = OrgInvitationServiceCreateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceCreateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceCreateRequest) ProtoMessage() {} + +func (x *OrgInvitationServiceCreateRequest) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceCreateRequest.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceCreateRequest) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{0} +} + +func (x *OrgInvitationServiceCreateRequest) GetOrganizationId() string { + if x != nil { + return x.OrganizationId + } + return "" +} + +func (x *OrgInvitationServiceCreateRequest) GetReceiverEmail() string { + if x != nil { + return x.ReceiverEmail + } + return "" +} + +type OrgInvitationServiceCreateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result *OrgInvitationItem `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` +} + +func (x *OrgInvitationServiceCreateResponse) Reset() { + *x = OrgInvitationServiceCreateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceCreateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceCreateResponse) ProtoMessage() {} + +func (x *OrgInvitationServiceCreateResponse) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceCreateResponse.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceCreateResponse) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{1} +} + +func (x *OrgInvitationServiceCreateResponse) GetResult() *OrgInvitationItem { + if x != nil { + return x.Result + } + return nil +} + +type OrgInvitationServiceRevokeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *OrgInvitationServiceRevokeRequest) Reset() { + *x = OrgInvitationServiceRevokeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceRevokeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceRevokeRequest) ProtoMessage() {} + +func (x *OrgInvitationServiceRevokeRequest) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceRevokeRequest.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceRevokeRequest) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{2} +} + +func (x *OrgInvitationServiceRevokeRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type OrgInvitationServiceRevokeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *OrgInvitationServiceRevokeResponse) Reset() { + *x = OrgInvitationServiceRevokeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceRevokeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceRevokeResponse) ProtoMessage() {} + +func (x *OrgInvitationServiceRevokeResponse) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceRevokeResponse.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceRevokeResponse) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{3} +} + +type OrgInvitationServiceListSentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *OrgInvitationServiceListSentRequest) Reset() { + *x = OrgInvitationServiceListSentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceListSentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceListSentRequest) ProtoMessage() {} + +func (x *OrgInvitationServiceListSentRequest) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceListSentRequest.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceListSentRequest) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{4} +} + +type OrgInvitationServiceListSentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result []*OrgInvitationItem `protobuf:"bytes,1,rep,name=result,proto3" json:"result,omitempty"` +} + +func (x *OrgInvitationServiceListSentResponse) Reset() { + *x = OrgInvitationServiceListSentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationServiceListSentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationServiceListSentResponse) ProtoMessage() {} + +func (x *OrgInvitationServiceListSentResponse) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationServiceListSentResponse.ProtoReflect.Descriptor instead. +func (*OrgInvitationServiceListSentResponse) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{5} +} + +func (x *OrgInvitationServiceListSentResponse) GetResult() []*OrgInvitationItem { + if x != nil { + return x.Result + } + return nil +} + +type OrgInvitationItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ReceiverEmail string `protobuf:"bytes,3,opt,name=receiver_email,json=receiverEmail,proto3" json:"receiver_email,omitempty"` + Sender *User `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` + Organization *Org `protobuf:"bytes,5,opt,name=organization,proto3" json:"organization,omitempty"` + Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *OrgInvitationItem) Reset() { + *x = OrgInvitationItem{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OrgInvitationItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OrgInvitationItem) ProtoMessage() {} + +func (x *OrgInvitationItem) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_org_invitation_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OrgInvitationItem.ProtoReflect.Descriptor instead. +func (*OrgInvitationItem) Descriptor() ([]byte, []int) { + return file_controlplane_v1_org_invitation_proto_rawDescGZIP(), []int{6} +} + +func (x *OrgInvitationItem) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *OrgInvitationItem) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *OrgInvitationItem) GetReceiverEmail() string { + if x != nil { + return x.ReceiverEmail + } + return "" +} + +func (x *OrgInvitationItem) GetSender() *User { + if x != nil { + return x.Sender + } + return nil +} + +func (x *OrgInvitationItem) GetOrganization() *Org { + if x != nil { + return x.Organization + } + return nil +} + +func (x *OrgInvitationItem) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +var File_controlplane_v1_org_invitation_proto protoreflect.FileDescriptor + +var file_controlplane_v1_org_invitation_proto_rawDesc = []byte{ + 0x0a, 0x24, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, + 0x31, 0x2f, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, + 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x86, 0x01, 0x0a, 0x21, 0x4f, + 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, + 0xb0, 0x01, 0x01, 0x52, 0x0e, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x60, 0x01, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x22, 0x60, 0x0a, 0x22, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3d, 0x0a, 0x21, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x24, 0x0a, 0x22, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x76, 0x6f, + 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x23, 0x4f, 0x72, + 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0x62, 0x0a, 0x24, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x86, 0x02, 0x0a, 0x11, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2d, 0x0a, + 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x0c, + 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xf5, + 0x02, 0x0a, 0x14, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x52, 0x65, + 0x76, 0x6f, 0x6b, 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x6b, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, + 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, + 0x08, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, + 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, + 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, + 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_controlplane_v1_org_invitation_proto_rawDescOnce sync.Once + file_controlplane_v1_org_invitation_proto_rawDescData = file_controlplane_v1_org_invitation_proto_rawDesc +) + +func file_controlplane_v1_org_invitation_proto_rawDescGZIP() []byte { + file_controlplane_v1_org_invitation_proto_rawDescOnce.Do(func() { + file_controlplane_v1_org_invitation_proto_rawDescData = protoimpl.X.CompressGZIP(file_controlplane_v1_org_invitation_proto_rawDescData) + }) + return file_controlplane_v1_org_invitation_proto_rawDescData +} + +var file_controlplane_v1_org_invitation_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_controlplane_v1_org_invitation_proto_goTypes = []interface{}{ + (*OrgInvitationServiceCreateRequest)(nil), // 0: controlplane.v1.OrgInvitationServiceCreateRequest + (*OrgInvitationServiceCreateResponse)(nil), // 1: controlplane.v1.OrgInvitationServiceCreateResponse + (*OrgInvitationServiceRevokeRequest)(nil), // 2: controlplane.v1.OrgInvitationServiceRevokeRequest + (*OrgInvitationServiceRevokeResponse)(nil), // 3: controlplane.v1.OrgInvitationServiceRevokeResponse + (*OrgInvitationServiceListSentRequest)(nil), // 4: controlplane.v1.OrgInvitationServiceListSentRequest + (*OrgInvitationServiceListSentResponse)(nil), // 5: controlplane.v1.OrgInvitationServiceListSentResponse + (*OrgInvitationItem)(nil), // 6: controlplane.v1.OrgInvitationItem + (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp + (*User)(nil), // 8: controlplane.v1.User + (*Org)(nil), // 9: controlplane.v1.Org +} +var file_controlplane_v1_org_invitation_proto_depIdxs = []int32{ + 6, // 0: controlplane.v1.OrgInvitationServiceCreateResponse.result:type_name -> controlplane.v1.OrgInvitationItem + 6, // 1: controlplane.v1.OrgInvitationServiceListSentResponse.result:type_name -> controlplane.v1.OrgInvitationItem + 7, // 2: controlplane.v1.OrgInvitationItem.created_at:type_name -> google.protobuf.Timestamp + 8, // 3: controlplane.v1.OrgInvitationItem.sender:type_name -> controlplane.v1.User + 9, // 4: controlplane.v1.OrgInvitationItem.organization:type_name -> controlplane.v1.Org + 0, // 5: controlplane.v1.OrgInvitationService.Create:input_type -> controlplane.v1.OrgInvitationServiceCreateRequest + 2, // 6: controlplane.v1.OrgInvitationService.Revoke:input_type -> controlplane.v1.OrgInvitationServiceRevokeRequest + 4, // 7: controlplane.v1.OrgInvitationService.ListSent:input_type -> controlplane.v1.OrgInvitationServiceListSentRequest + 1, // 8: controlplane.v1.OrgInvitationService.Create:output_type -> controlplane.v1.OrgInvitationServiceCreateResponse + 3, // 9: controlplane.v1.OrgInvitationService.Revoke:output_type -> controlplane.v1.OrgInvitationServiceRevokeResponse + 5, // 10: controlplane.v1.OrgInvitationService.ListSent:output_type -> controlplane.v1.OrgInvitationServiceListSentResponse + 8, // [8:11] is the sub-list for method output_type + 5, // [5:8] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_controlplane_v1_org_invitation_proto_init() } +func file_controlplane_v1_org_invitation_proto_init() { + if File_controlplane_v1_org_invitation_proto != nil { + return + } + file_controlplane_v1_response_messages_proto_init() + if !protoimpl.UnsafeEnabled { + file_controlplane_v1_org_invitation_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceCreateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceCreateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceRevokeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceRevokeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceListSentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationServiceListSentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_org_invitation_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OrgInvitationItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controlplane_v1_org_invitation_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_controlplane_v1_org_invitation_proto_goTypes, + DependencyIndexes: file_controlplane_v1_org_invitation_proto_depIdxs, + MessageInfos: file_controlplane_v1_org_invitation_proto_msgTypes, + }.Build() + File_controlplane_v1_org_invitation_proto = out.File + file_controlplane_v1_org_invitation_proto_rawDesc = nil + file_controlplane_v1_org_invitation_proto_goTypes = nil + file_controlplane_v1_org_invitation_proto_depIdxs = nil +} diff --git a/app/controlplane/api/controlplane/v1/org_invitation.pb.validate.go b/app/controlplane/api/controlplane/v1/org_invitation.pb.validate.go new file mode 100644 index 000000000..c27eed740 --- /dev/null +++ b/app/controlplane/api/controlplane/v1/org_invitation.pb.validate.go @@ -0,0 +1,1029 @@ +// Code generated by protoc-gen-validate. DO NOT EDIT. +// source: controlplane/v1/org_invitation.proto + +package v1 + +import ( + "bytes" + "errors" + "fmt" + "net" + "net/mail" + "net/url" + "regexp" + "sort" + "strings" + "time" + "unicode/utf8" + + "google.golang.org/protobuf/types/known/anypb" +) + +// ensure the imports are used +var ( + _ = bytes.MinRead + _ = errors.New("") + _ = fmt.Print + _ = utf8.UTFMax + _ = (*regexp.Regexp)(nil) + _ = (*strings.Reader)(nil) + _ = net.IPv4len + _ = time.Duration(0) + _ = (*url.URL)(nil) + _ = (*mail.Address)(nil) + _ = anypb.Any{} + _ = sort.Sort +) + +// define the regex for a UUID once up-front +var _org_invitation_uuidPattern = regexp.MustCompile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") + +// Validate checks the field values on OrgInvitationServiceCreateRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *OrgInvitationServiceCreateRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceCreateRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceCreateRequestMultiError, or nil if none found. +func (m *OrgInvitationServiceCreateRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceCreateRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if err := m._validateUuid(m.GetOrganizationId()); err != nil { + err = OrgInvitationServiceCreateRequestValidationError{ + field: "OrganizationId", + reason: "value must be a valid UUID", + cause: err, + } + if !all { + return err + } + errors = append(errors, err) + } + + if err := m._validateEmail(m.GetReceiverEmail()); err != nil { + err = OrgInvitationServiceCreateRequestValidationError{ + field: "ReceiverEmail", + reason: "value must be a valid email address", + cause: err, + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return OrgInvitationServiceCreateRequestMultiError(errors) + } + + return nil +} + +func (m *OrgInvitationServiceCreateRequest) _validateHostname(host string) error { + s := strings.ToLower(strings.TrimSuffix(host, ".")) + + if len(host) > 253 { + return errors.New("hostname cannot exceed 253 characters") + } + + for _, part := range strings.Split(s, ".") { + if l := len(part); l == 0 || l > 63 { + return errors.New("hostname part must be non-empty and cannot exceed 63 characters") + } + + if part[0] == '-' { + return errors.New("hostname parts cannot begin with hyphens") + } + + if part[len(part)-1] == '-' { + return errors.New("hostname parts cannot end with hyphens") + } + + for _, r := range part { + if (r < 'a' || r > 'z') && (r < '0' || r > '9') && r != '-' { + return fmt.Errorf("hostname parts can only contain alphanumeric characters or hyphens, got %q", string(r)) + } + } + } + + return nil +} + +func (m *OrgInvitationServiceCreateRequest) _validateEmail(addr string) error { + a, err := mail.ParseAddress(addr) + if err != nil { + return err + } + addr = a.Address + + if len(addr) > 254 { + return errors.New("email addresses cannot exceed 254 characters") + } + + parts := strings.SplitN(addr, "@", 2) + + if len(parts[0]) > 64 { + return errors.New("email address local phrase cannot exceed 64 characters") + } + + return m._validateHostname(parts[1]) +} + +func (m *OrgInvitationServiceCreateRequest) _validateUuid(uuid string) error { + if matched := _org_invitation_uuidPattern.MatchString(uuid); !matched { + return errors.New("invalid uuid format") + } + + return nil +} + +// OrgInvitationServiceCreateRequestMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceCreateRequest.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceCreateRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceCreateRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceCreateRequestMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceCreateRequestValidationError is the validation error +// returned by OrgInvitationServiceCreateRequest.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceCreateRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceCreateRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceCreateRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceCreateRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceCreateRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceCreateRequestValidationError) ErrorName() string { + return "OrgInvitationServiceCreateRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceCreateRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceCreateRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceCreateRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceCreateRequestValidationError{} + +// Validate checks the field values on OrgInvitationServiceCreateResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *OrgInvitationServiceCreateResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceCreateResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceCreateResponseMultiError, or nil if none found. +func (m *OrgInvitationServiceCreateResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceCreateResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetResult()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, OrgInvitationServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, OrgInvitationServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetResult()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return OrgInvitationServiceCreateResponseValidationError{ + field: "Result", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return OrgInvitationServiceCreateResponseMultiError(errors) + } + + return nil +} + +// OrgInvitationServiceCreateResponseMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceCreateResponse.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceCreateResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceCreateResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceCreateResponseMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceCreateResponseValidationError is the validation error +// returned by OrgInvitationServiceCreateResponse.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceCreateResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceCreateResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceCreateResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceCreateResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceCreateResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceCreateResponseValidationError) ErrorName() string { + return "OrgInvitationServiceCreateResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceCreateResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceCreateResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceCreateResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceCreateResponseValidationError{} + +// Validate checks the field values on OrgInvitationServiceRevokeRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *OrgInvitationServiceRevokeRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceRevokeRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceRevokeRequestMultiError, or nil if none found. +func (m *OrgInvitationServiceRevokeRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceRevokeRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if err := m._validateUuid(m.GetId()); err != nil { + err = OrgInvitationServiceRevokeRequestValidationError{ + field: "Id", + reason: "value must be a valid UUID", + cause: err, + } + if !all { + return err + } + errors = append(errors, err) + } + + if len(errors) > 0 { + return OrgInvitationServiceRevokeRequestMultiError(errors) + } + + return nil +} + +func (m *OrgInvitationServiceRevokeRequest) _validateUuid(uuid string) error { + if matched := _org_invitation_uuidPattern.MatchString(uuid); !matched { + return errors.New("invalid uuid format") + } + + return nil +} + +// OrgInvitationServiceRevokeRequestMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceRevokeRequest.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceRevokeRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceRevokeRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceRevokeRequestMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceRevokeRequestValidationError is the validation error +// returned by OrgInvitationServiceRevokeRequest.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceRevokeRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceRevokeRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceRevokeRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceRevokeRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceRevokeRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceRevokeRequestValidationError) ErrorName() string { + return "OrgInvitationServiceRevokeRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceRevokeRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceRevokeRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceRevokeRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceRevokeRequestValidationError{} + +// Validate checks the field values on OrgInvitationServiceRevokeResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *OrgInvitationServiceRevokeResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceRevokeResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceRevokeResponseMultiError, or nil if none found. +func (m *OrgInvitationServiceRevokeResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceRevokeResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return OrgInvitationServiceRevokeResponseMultiError(errors) + } + + return nil +} + +// OrgInvitationServiceRevokeResponseMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceRevokeResponse.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceRevokeResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceRevokeResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceRevokeResponseMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceRevokeResponseValidationError is the validation error +// returned by OrgInvitationServiceRevokeResponse.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceRevokeResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceRevokeResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceRevokeResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceRevokeResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceRevokeResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceRevokeResponseValidationError) ErrorName() string { + return "OrgInvitationServiceRevokeResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceRevokeResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceRevokeResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceRevokeResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceRevokeResponseValidationError{} + +// Validate checks the field values on OrgInvitationServiceListSentRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *OrgInvitationServiceListSentRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceListSentRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceListSentRequestMultiError, or nil if none found. +func (m *OrgInvitationServiceListSentRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceListSentRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return OrgInvitationServiceListSentRequestMultiError(errors) + } + + return nil +} + +// OrgInvitationServiceListSentRequestMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceListSentRequest.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceListSentRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceListSentRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceListSentRequestMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceListSentRequestValidationError is the validation error +// returned by OrgInvitationServiceListSentRequest.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceListSentRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceListSentRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceListSentRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceListSentRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceListSentRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceListSentRequestValidationError) ErrorName() string { + return "OrgInvitationServiceListSentRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceListSentRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceListSentRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceListSentRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceListSentRequestValidationError{} + +// Validate checks the field values on OrgInvitationServiceListSentResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the first error encountered is returned, or nil if +// there are no violations. +func (m *OrgInvitationServiceListSentResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationServiceListSentResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// OrgInvitationServiceListSentResponseMultiError, or nil if none found. +func (m *OrgInvitationServiceListSentResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationServiceListSentResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + for idx, item := range m.GetResult() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, OrgInvitationServiceListSentResponseValidationError{ + field: fmt.Sprintf("Result[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, OrgInvitationServiceListSentResponseValidationError{ + field: fmt.Sprintf("Result[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return OrgInvitationServiceListSentResponseValidationError{ + field: fmt.Sprintf("Result[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return OrgInvitationServiceListSentResponseMultiError(errors) + } + + return nil +} + +// OrgInvitationServiceListSentResponseMultiError is an error wrapping multiple +// validation errors returned by +// OrgInvitationServiceListSentResponse.ValidateAll() if the designated +// constraints aren't met. +type OrgInvitationServiceListSentResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationServiceListSentResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationServiceListSentResponseMultiError) AllErrors() []error { return m } + +// OrgInvitationServiceListSentResponseValidationError is the validation error +// returned by OrgInvitationServiceListSentResponse.Validate if the designated +// constraints aren't met. +type OrgInvitationServiceListSentResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationServiceListSentResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationServiceListSentResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationServiceListSentResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationServiceListSentResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationServiceListSentResponseValidationError) ErrorName() string { + return "OrgInvitationServiceListSentResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationServiceListSentResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationServiceListSentResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationServiceListSentResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationServiceListSentResponseValidationError{} + +// Validate checks the field values on OrgInvitationItem with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *OrgInvitationItem) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on OrgInvitationItem with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// OrgInvitationItemMultiError, or nil if none found. +func (m *OrgInvitationItem) ValidateAll() error { + return m.validate(true) +} + +func (m *OrgInvitationItem) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + if all { + switch v := interface{}(m.GetCreatedAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "CreatedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "CreatedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCreatedAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return OrgInvitationItemValidationError{ + field: "CreatedAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for ReceiverEmail + + if all { + switch v := interface{}(m.GetSender()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "Sender", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "Sender", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSender()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return OrgInvitationItemValidationError{ + field: "Sender", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetOrganization()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "Organization", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, OrgInvitationItemValidationError{ + field: "Organization", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetOrganization()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return OrgInvitationItemValidationError{ + field: "Organization", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for Status + + if len(errors) > 0 { + return OrgInvitationItemMultiError(errors) + } + + return nil +} + +// OrgInvitationItemMultiError is an error wrapping multiple validation errors +// returned by OrgInvitationItem.ValidateAll() if the designated constraints +// aren't met. +type OrgInvitationItemMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m OrgInvitationItemMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m OrgInvitationItemMultiError) AllErrors() []error { return m } + +// OrgInvitationItemValidationError is the validation error returned by +// OrgInvitationItem.Validate if the designated constraints aren't met. +type OrgInvitationItemValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e OrgInvitationItemValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e OrgInvitationItemValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e OrgInvitationItemValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e OrgInvitationItemValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e OrgInvitationItemValidationError) ErrorName() string { + return "OrgInvitationItemValidationError" +} + +// Error satisfies the builtin error interface +func (e OrgInvitationItemValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sOrgInvitationItem.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = OrgInvitationItemValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = OrgInvitationItemValidationError{} diff --git a/app/controlplane/api/controlplane/v1/org_invitation.proto b/app/controlplane/api/controlplane/v1/org_invitation.proto new file mode 100644 index 000000000..fa7de2b6a --- /dev/null +++ b/app/controlplane/api/controlplane/v1/org_invitation.proto @@ -0,0 +1,63 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package controlplane.v1; + +import "google/protobuf/timestamp.proto"; +import "validate/validate.proto"; +import "controlplane/v1/response_messages.proto"; + +option go_package = "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1;v1"; + +service OrgInvitationService { + // Create an invitation for a user to join an organization. + rpc Create(OrgInvitationServiceCreateRequest) returns (OrgInvitationServiceCreateResponse); + // Revoke an invitation. + rpc Revoke(OrgInvitationServiceRevokeRequest) returns (OrgInvitationServiceRevokeResponse); + // List all invitations sent by the current user. + rpc ListSent(OrgInvitationServiceListSentRequest) returns (OrgInvitationServiceListSentResponse); +} + +message OrgInvitationServiceCreateRequest { + string organization_id = 1 [(validate.rules).string.uuid = true]; + string receiver_email = 2 [(validate.rules).string.email = true]; +} + +message OrgInvitationServiceCreateResponse { + OrgInvitationItem result = 1; +} + +message OrgInvitationServiceRevokeRequest { + string id = 1 [(validate.rules).string.uuid = true]; +} + +message OrgInvitationServiceRevokeResponse {} + +message OrgInvitationServiceListSentRequest {} + +message OrgInvitationServiceListSentResponse { + repeated OrgInvitationItem result = 1; +} + +message OrgInvitationItem { + string id = 1; + google.protobuf.Timestamp created_at = 2; + string receiver_email = 3; + User sender = 4; + Org organization = 5; + string status = 6; +} diff --git a/app/controlplane/api/controlplane/v1/org_invitation_grpc.pb.go b/app/controlplane/api/controlplane/v1/org_invitation_grpc.pb.go new file mode 100644 index 000000000..43f6393fd --- /dev/null +++ b/app/controlplane/api/controlplane/v1/org_invitation_grpc.pb.go @@ -0,0 +1,204 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: controlplane/v1/org_invitation.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + OrgInvitationService_Create_FullMethodName = "/controlplane.v1.OrgInvitationService/Create" + OrgInvitationService_Revoke_FullMethodName = "/controlplane.v1.OrgInvitationService/Revoke" + OrgInvitationService_ListSent_FullMethodName = "/controlplane.v1.OrgInvitationService/ListSent" +) + +// OrgInvitationServiceClient is the client API for OrgInvitationService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type OrgInvitationServiceClient interface { + // Create an invitation for a user to join an organization. + Create(ctx context.Context, in *OrgInvitationServiceCreateRequest, opts ...grpc.CallOption) (*OrgInvitationServiceCreateResponse, error) + // Revoke an invitation. + Revoke(ctx context.Context, in *OrgInvitationServiceRevokeRequest, opts ...grpc.CallOption) (*OrgInvitationServiceRevokeResponse, error) + // List all invitations sent by the current user. + ListSent(ctx context.Context, in *OrgInvitationServiceListSentRequest, opts ...grpc.CallOption) (*OrgInvitationServiceListSentResponse, error) +} + +type orgInvitationServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewOrgInvitationServiceClient(cc grpc.ClientConnInterface) OrgInvitationServiceClient { + return &orgInvitationServiceClient{cc} +} + +func (c *orgInvitationServiceClient) Create(ctx context.Context, in *OrgInvitationServiceCreateRequest, opts ...grpc.CallOption) (*OrgInvitationServiceCreateResponse, error) { + out := new(OrgInvitationServiceCreateResponse) + err := c.cc.Invoke(ctx, OrgInvitationService_Create_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *orgInvitationServiceClient) Revoke(ctx context.Context, in *OrgInvitationServiceRevokeRequest, opts ...grpc.CallOption) (*OrgInvitationServiceRevokeResponse, error) { + out := new(OrgInvitationServiceRevokeResponse) + err := c.cc.Invoke(ctx, OrgInvitationService_Revoke_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *orgInvitationServiceClient) ListSent(ctx context.Context, in *OrgInvitationServiceListSentRequest, opts ...grpc.CallOption) (*OrgInvitationServiceListSentResponse, error) { + out := new(OrgInvitationServiceListSentResponse) + err := c.cc.Invoke(ctx, OrgInvitationService_ListSent_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// OrgInvitationServiceServer is the server API for OrgInvitationService service. +// All implementations must embed UnimplementedOrgInvitationServiceServer +// for forward compatibility +type OrgInvitationServiceServer interface { + // Create an invitation for a user to join an organization. + Create(context.Context, *OrgInvitationServiceCreateRequest) (*OrgInvitationServiceCreateResponse, error) + // Revoke an invitation. + Revoke(context.Context, *OrgInvitationServiceRevokeRequest) (*OrgInvitationServiceRevokeResponse, error) + // List all invitations sent by the current user. + ListSent(context.Context, *OrgInvitationServiceListSentRequest) (*OrgInvitationServiceListSentResponse, error) + mustEmbedUnimplementedOrgInvitationServiceServer() +} + +// UnimplementedOrgInvitationServiceServer must be embedded to have forward compatible implementations. +type UnimplementedOrgInvitationServiceServer struct { +} + +func (UnimplementedOrgInvitationServiceServer) Create(context.Context, *OrgInvitationServiceCreateRequest) (*OrgInvitationServiceCreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (UnimplementedOrgInvitationServiceServer) Revoke(context.Context, *OrgInvitationServiceRevokeRequest) (*OrgInvitationServiceRevokeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Revoke not implemented") +} +func (UnimplementedOrgInvitationServiceServer) ListSent(context.Context, *OrgInvitationServiceListSentRequest) (*OrgInvitationServiceListSentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListSent not implemented") +} +func (UnimplementedOrgInvitationServiceServer) mustEmbedUnimplementedOrgInvitationServiceServer() {} + +// UnsafeOrgInvitationServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to OrgInvitationServiceServer will +// result in compilation errors. +type UnsafeOrgInvitationServiceServer interface { + mustEmbedUnimplementedOrgInvitationServiceServer() +} + +func RegisterOrgInvitationServiceServer(s grpc.ServiceRegistrar, srv OrgInvitationServiceServer) { + s.RegisterService(&OrgInvitationService_ServiceDesc, srv) +} + +func _OrgInvitationService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OrgInvitationServiceCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrgInvitationServiceServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OrgInvitationService_Create_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrgInvitationServiceServer).Create(ctx, req.(*OrgInvitationServiceCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OrgInvitationService_Revoke_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OrgInvitationServiceRevokeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrgInvitationServiceServer).Revoke(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OrgInvitationService_Revoke_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrgInvitationServiceServer).Revoke(ctx, req.(*OrgInvitationServiceRevokeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _OrgInvitationService_ListSent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OrgInvitationServiceListSentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(OrgInvitationServiceServer).ListSent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: OrgInvitationService_ListSent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(OrgInvitationServiceServer).ListSent(ctx, req.(*OrgInvitationServiceListSentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// OrgInvitationService_ServiceDesc is the grpc.ServiceDesc for OrgInvitationService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var OrgInvitationService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "controlplane.v1.OrgInvitationService", + HandlerType: (*OrgInvitationServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Create", + Handler: _OrgInvitationService_Create_Handler, + }, + { + MethodName: "Revoke", + Handler: _OrgInvitationService_Revoke_Handler, + }, + { + MethodName: "ListSent", + Handler: _OrgInvitationService_ListSent_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "controlplane/v1/org_invitation.proto", +} diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/org_invitation.ts b/app/controlplane/api/gen/frontend/controlplane/v1/org_invitation.ts new file mode 100644 index 000000000..d1b117eb9 --- /dev/null +++ b/app/controlplane/api/gen/frontend/controlplane/v1/org_invitation.ts @@ -0,0 +1,791 @@ +/* eslint-disable */ +import { grpc } from "@improbable-eng/grpc-web"; +import { BrowserHeaders } from "browser-headers"; +import _m0 from "protobufjs/minimal"; +import { Timestamp } from "../../google/protobuf/timestamp"; +import { Org, User } from "./response_messages"; + +export const protobufPackage = "controlplane.v1"; + +export interface OrgInvitationServiceCreateRequest { + organizationId: string; + receiverEmail: string; +} + +export interface OrgInvitationServiceCreateResponse { + result?: OrgInvitationItem; +} + +export interface OrgInvitationServiceRevokeRequest { + id: string; +} + +export interface OrgInvitationServiceRevokeResponse { +} + +export interface OrgInvitationServiceListSentRequest { +} + +export interface OrgInvitationServiceListSentResponse { + result: OrgInvitationItem[]; +} + +export interface OrgInvitationItem { + id: string; + createdAt?: Date; + receiverEmail: string; + sender?: User; + organization?: Org; + status: string; +} + +function createBaseOrgInvitationServiceCreateRequest(): OrgInvitationServiceCreateRequest { + return { organizationId: "", receiverEmail: "" }; +} + +export const OrgInvitationServiceCreateRequest = { + encode(message: OrgInvitationServiceCreateRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.organizationId !== "") { + writer.uint32(10).string(message.organizationId); + } + if (message.receiverEmail !== "") { + writer.uint32(18).string(message.receiverEmail); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceCreateRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceCreateRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.organizationId = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.receiverEmail = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OrgInvitationServiceCreateRequest { + return { + organizationId: isSet(object.organizationId) ? String(object.organizationId) : "", + receiverEmail: isSet(object.receiverEmail) ? String(object.receiverEmail) : "", + }; + }, + + toJSON(message: OrgInvitationServiceCreateRequest): unknown { + const obj: any = {}; + message.organizationId !== undefined && (obj.organizationId = message.organizationId); + message.receiverEmail !== undefined && (obj.receiverEmail = message.receiverEmail); + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceCreateRequest { + return OrgInvitationServiceCreateRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): OrgInvitationServiceCreateRequest { + const message = createBaseOrgInvitationServiceCreateRequest(); + message.organizationId = object.organizationId ?? ""; + message.receiverEmail = object.receiverEmail ?? ""; + return message; + }, +}; + +function createBaseOrgInvitationServiceCreateResponse(): OrgInvitationServiceCreateResponse { + return { result: undefined }; +} + +export const OrgInvitationServiceCreateResponse = { + encode(message: OrgInvitationServiceCreateResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.result !== undefined) { + OrgInvitationItem.encode(message.result, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceCreateResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceCreateResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.result = OrgInvitationItem.decode(reader, reader.uint32()); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OrgInvitationServiceCreateResponse { + return { result: isSet(object.result) ? OrgInvitationItem.fromJSON(object.result) : undefined }; + }, + + toJSON(message: OrgInvitationServiceCreateResponse): unknown { + const obj: any = {}; + message.result !== undefined && + (obj.result = message.result ? OrgInvitationItem.toJSON(message.result) : undefined); + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceCreateResponse { + return OrgInvitationServiceCreateResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): OrgInvitationServiceCreateResponse { + const message = createBaseOrgInvitationServiceCreateResponse(); + message.result = (object.result !== undefined && object.result !== null) + ? OrgInvitationItem.fromPartial(object.result) + : undefined; + return message; + }, +}; + +function createBaseOrgInvitationServiceRevokeRequest(): OrgInvitationServiceRevokeRequest { + return { id: "" }; +} + +export const OrgInvitationServiceRevokeRequest = { + encode(message: OrgInvitationServiceRevokeRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.id !== "") { + writer.uint32(10).string(message.id); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceRevokeRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceRevokeRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.id = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OrgInvitationServiceRevokeRequest { + return { id: isSet(object.id) ? String(object.id) : "" }; + }, + + toJSON(message: OrgInvitationServiceRevokeRequest): unknown { + const obj: any = {}; + message.id !== undefined && (obj.id = message.id); + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceRevokeRequest { + return OrgInvitationServiceRevokeRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): OrgInvitationServiceRevokeRequest { + const message = createBaseOrgInvitationServiceRevokeRequest(); + message.id = object.id ?? ""; + return message; + }, +}; + +function createBaseOrgInvitationServiceRevokeResponse(): OrgInvitationServiceRevokeResponse { + return {}; +} + +export const OrgInvitationServiceRevokeResponse = { + encode(_: OrgInvitationServiceRevokeResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceRevokeResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceRevokeResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): OrgInvitationServiceRevokeResponse { + return {}; + }, + + toJSON(_: OrgInvitationServiceRevokeResponse): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceRevokeResponse { + return OrgInvitationServiceRevokeResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + _: I, + ): OrgInvitationServiceRevokeResponse { + const message = createBaseOrgInvitationServiceRevokeResponse(); + return message; + }, +}; + +function createBaseOrgInvitationServiceListSentRequest(): OrgInvitationServiceListSentRequest { + return {}; +} + +export const OrgInvitationServiceListSentRequest = { + encode(_: OrgInvitationServiceListSentRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceListSentRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceListSentRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): OrgInvitationServiceListSentRequest { + return {}; + }, + + toJSON(_: OrgInvitationServiceListSentRequest): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceListSentRequest { + return OrgInvitationServiceListSentRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + _: I, + ): OrgInvitationServiceListSentRequest { + const message = createBaseOrgInvitationServiceListSentRequest(); + return message; + }, +}; + +function createBaseOrgInvitationServiceListSentResponse(): OrgInvitationServiceListSentResponse { + return { result: [] }; +} + +export const OrgInvitationServiceListSentResponse = { + encode(message: OrgInvitationServiceListSentResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + for (const v of message.result) { + OrgInvitationItem.encode(v!, writer.uint32(10).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationServiceListSentResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationServiceListSentResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.result.push(OrgInvitationItem.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OrgInvitationServiceListSentResponse { + return { + result: Array.isArray(object?.result) ? object.result.map((e: any) => OrgInvitationItem.fromJSON(e)) : [], + }; + }, + + toJSON(message: OrgInvitationServiceListSentResponse): unknown { + const obj: any = {}; + if (message.result) { + obj.result = message.result.map((e) => e ? OrgInvitationItem.toJSON(e) : undefined); + } else { + obj.result = []; + } + return obj; + }, + + create, I>>( + base?: I, + ): OrgInvitationServiceListSentResponse { + return OrgInvitationServiceListSentResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): OrgInvitationServiceListSentResponse { + const message = createBaseOrgInvitationServiceListSentResponse(); + message.result = object.result?.map((e) => OrgInvitationItem.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseOrgInvitationItem(): OrgInvitationItem { + return { id: "", createdAt: undefined, receiverEmail: "", sender: undefined, organization: undefined, status: "" }; +} + +export const OrgInvitationItem = { + encode(message: OrgInvitationItem, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.id !== "") { + writer.uint32(10).string(message.id); + } + if (message.createdAt !== undefined) { + Timestamp.encode(toTimestamp(message.createdAt), writer.uint32(18).fork()).ldelim(); + } + if (message.receiverEmail !== "") { + writer.uint32(26).string(message.receiverEmail); + } + if (message.sender !== undefined) { + User.encode(message.sender, writer.uint32(34).fork()).ldelim(); + } + if (message.organization !== undefined) { + Org.encode(message.organization, writer.uint32(42).fork()).ldelim(); + } + if (message.status !== "") { + writer.uint32(50).string(message.status); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OrgInvitationItem { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOrgInvitationItem(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.id = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.createdAt = fromTimestamp(Timestamp.decode(reader, reader.uint32())); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.receiverEmail = reader.string(); + continue; + case 4: + if (tag !== 34) { + break; + } + + message.sender = User.decode(reader, reader.uint32()); + continue; + case 5: + if (tag !== 42) { + break; + } + + message.organization = Org.decode(reader, reader.uint32()); + continue; + case 6: + if (tag !== 50) { + break; + } + + message.status = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OrgInvitationItem { + return { + id: isSet(object.id) ? String(object.id) : "", + createdAt: isSet(object.createdAt) ? fromJsonTimestamp(object.createdAt) : undefined, + receiverEmail: isSet(object.receiverEmail) ? String(object.receiverEmail) : "", + sender: isSet(object.sender) ? User.fromJSON(object.sender) : undefined, + organization: isSet(object.organization) ? Org.fromJSON(object.organization) : undefined, + status: isSet(object.status) ? String(object.status) : "", + }; + }, + + toJSON(message: OrgInvitationItem): unknown { + const obj: any = {}; + message.id !== undefined && (obj.id = message.id); + message.createdAt !== undefined && (obj.createdAt = message.createdAt.toISOString()); + message.receiverEmail !== undefined && (obj.receiverEmail = message.receiverEmail); + message.sender !== undefined && (obj.sender = message.sender ? User.toJSON(message.sender) : undefined); + message.organization !== undefined && + (obj.organization = message.organization ? Org.toJSON(message.organization) : undefined); + message.status !== undefined && (obj.status = message.status); + return obj; + }, + + create, I>>(base?: I): OrgInvitationItem { + return OrgInvitationItem.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): OrgInvitationItem { + const message = createBaseOrgInvitationItem(); + message.id = object.id ?? ""; + message.createdAt = object.createdAt ?? undefined; + message.receiverEmail = object.receiverEmail ?? ""; + message.sender = (object.sender !== undefined && object.sender !== null) + ? User.fromPartial(object.sender) + : undefined; + message.organization = (object.organization !== undefined && object.organization !== null) + ? Org.fromPartial(object.organization) + : undefined; + message.status = object.status ?? ""; + return message; + }, +}; + +export interface OrgInvitationService { + /** Create an invitation for a user to join an organization. */ + Create( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise; + /** Revoke an invitation. */ + Revoke( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise; + /** List all invitations sent by the current user. */ + ListSent( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise; +} + +export class OrgInvitationServiceClientImpl implements OrgInvitationService { + private readonly rpc: Rpc; + + constructor(rpc: Rpc) { + this.rpc = rpc; + this.Create = this.Create.bind(this); + this.Revoke = this.Revoke.bind(this); + this.ListSent = this.ListSent.bind(this); + } + + Create( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise { + return this.rpc.unary( + OrgInvitationServiceCreateDesc, + OrgInvitationServiceCreateRequest.fromPartial(request), + metadata, + ); + } + + Revoke( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise { + return this.rpc.unary( + OrgInvitationServiceRevokeDesc, + OrgInvitationServiceRevokeRequest.fromPartial(request), + metadata, + ); + } + + ListSent( + request: DeepPartial, + metadata?: grpc.Metadata, + ): Promise { + return this.rpc.unary( + OrgInvitationServiceListSentDesc, + OrgInvitationServiceListSentRequest.fromPartial(request), + metadata, + ); + } +} + +export const OrgInvitationServiceDesc = { serviceName: "controlplane.v1.OrgInvitationService" }; + +export const OrgInvitationServiceCreateDesc: UnaryMethodDefinitionish = { + methodName: "Create", + service: OrgInvitationServiceDesc, + requestStream: false, + responseStream: false, + requestType: { + serializeBinary() { + return OrgInvitationServiceCreateRequest.encode(this).finish(); + }, + } as any, + responseType: { + deserializeBinary(data: Uint8Array) { + const value = OrgInvitationServiceCreateResponse.decode(data); + return { + ...value, + toObject() { + return value; + }, + }; + }, + } as any, +}; + +export const OrgInvitationServiceRevokeDesc: UnaryMethodDefinitionish = { + methodName: "Revoke", + service: OrgInvitationServiceDesc, + requestStream: false, + responseStream: false, + requestType: { + serializeBinary() { + return OrgInvitationServiceRevokeRequest.encode(this).finish(); + }, + } as any, + responseType: { + deserializeBinary(data: Uint8Array) { + const value = OrgInvitationServiceRevokeResponse.decode(data); + return { + ...value, + toObject() { + return value; + }, + }; + }, + } as any, +}; + +export const OrgInvitationServiceListSentDesc: UnaryMethodDefinitionish = { + methodName: "ListSent", + service: OrgInvitationServiceDesc, + requestStream: false, + responseStream: false, + requestType: { + serializeBinary() { + return OrgInvitationServiceListSentRequest.encode(this).finish(); + }, + } as any, + responseType: { + deserializeBinary(data: Uint8Array) { + const value = OrgInvitationServiceListSentResponse.decode(data); + return { + ...value, + toObject() { + return value; + }, + }; + }, + } as any, +}; + +interface UnaryMethodDefinitionishR extends grpc.UnaryMethodDefinition { + requestStream: any; + responseStream: any; +} + +type UnaryMethodDefinitionish = UnaryMethodDefinitionishR; + +interface Rpc { + unary( + methodDesc: T, + request: any, + metadata: grpc.Metadata | undefined, + ): Promise; +} + +export class GrpcWebImpl { + private host: string; + private options: { + transport?: grpc.TransportFactory; + + debug?: boolean; + metadata?: grpc.Metadata; + upStreamRetryCodes?: number[]; + }; + + constructor( + host: string, + options: { + transport?: grpc.TransportFactory; + + debug?: boolean; + metadata?: grpc.Metadata; + upStreamRetryCodes?: number[]; + }, + ) { + this.host = host; + this.options = options; + } + + unary( + methodDesc: T, + _request: any, + metadata: grpc.Metadata | undefined, + ): Promise { + const request = { ..._request, ...methodDesc.requestType }; + const maybeCombinedMetadata = metadata && this.options.metadata + ? new BrowserHeaders({ ...this.options?.metadata.headersMap, ...metadata?.headersMap }) + : metadata || this.options.metadata; + return new Promise((resolve, reject) => { + grpc.unary(methodDesc, { + request, + host: this.host, + metadata: maybeCombinedMetadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (response.status === grpc.Code.OK) { + resolve(response.message!.toObject()); + } else { + const err = new GrpcWebError(response.statusMessage, response.status, response.trailers); + reject(err); + } + }, + }); + }); + } +} + +declare var self: any | undefined; +declare var window: any | undefined; +declare var global: any | undefined; +var tsProtoGlobalThis: any = (() => { + if (typeof globalThis !== "undefined") { + return globalThis; + } + if (typeof self !== "undefined") { + return self; + } + if (typeof window !== "undefined") { + return window; + } + if (typeof global !== "undefined") { + return global; + } + throw "Unable to locate global object"; +})(); + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +function toTimestamp(date: Date): Timestamp { + const seconds = date.getTime() / 1_000; + const nanos = (date.getTime() % 1_000) * 1_000_000; + return { seconds, nanos }; +} + +function fromTimestamp(t: Timestamp): Date { + let millis = (t.seconds || 0) * 1_000; + millis += (t.nanos || 0) / 1_000_000; + return new Date(millis); +} + +function fromJsonTimestamp(o: any): Date { + if (o instanceof Date) { + return o; + } else if (typeof o === "string") { + return new Date(o); + } else { + return fromTimestamp(Timestamp.fromJSON(o)); + } +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export class GrpcWebError extends tsProtoGlobalThis.Error { + constructor(message: string, public code: grpc.Code, public metadata: grpc.Metadata) { + super(message); + } +} diff --git a/app/controlplane/cmd/wire_gen.go b/app/controlplane/cmd/wire_gen.go index e337e7a6a..96950c377 100644 --- a/app/controlplane/cmd/wire_gen.go +++ b/app/controlplane/cmd/wire_gen.go @@ -69,8 +69,14 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l workflowUseCase := biz.NewWorkflowUsecase(workflowRepo, workflowContractUseCase, logger) v2 := serviceOpts(logger) workflowService := service.NewWorkflowService(workflowUseCase, v2...) + orgInvitationRepo := data.NewOrgInvitation(dataData, logger) + orgInvitationUseCase, err := biz.NewOrgInvitationUseCase(orgInvitationRepo, membershipRepo, userRepo, logger) + if err != nil { + cleanup() + return nil, nil, err + } confServer := bootstrap.Server - authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, casBackendUseCase, auth, confServer, v2...) + authService, err := service.NewAuthService(userUseCase, organizationUseCase, membershipUseCase, casBackendUseCase, orgInvitationUseCase, auth, confServer, v2...) if err != nil { cleanup() return nil, nil, err @@ -126,6 +132,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l cleanup() return nil, nil, err } + orgInvitationService := service.NewOrgInvitationService(orgInvitationUseCase, v2...) opts := &server.Opts{ UserUseCase: userUseCase, RobotAccountUseCase: robotAccountUseCase, @@ -145,6 +152,7 @@ func wireApp(bootstrap *conf.Bootstrap, readerWriter credentials.ReaderWriter, l OrganizationSvc: organizationService, CASBackendSvc: casBackendService, CASRedirectSvc: casRedirectService, + OrgInvitationSvc: orgInvitationService, Logger: logger, ServerConfig: confServer, AuthConfig: auth, diff --git a/app/controlplane/internal/biz/biz.go b/app/controlplane/internal/biz/biz.go index e82286930..4269aa853 100644 --- a/app/controlplane/internal/biz/biz.go +++ b/app/controlplane/internal/biz/biz.go @@ -31,6 +31,7 @@ var ProviderSet = wire.NewSet( NewIntegrationUseCase, NewMembershipUseCase, NewCASClientUseCase, + NewOrgInvitationUseCase, NewAttestationUseCase, NewWorkflowRunExpirerUseCase, NewCASMappingUseCase, diff --git a/app/controlplane/internal/biz/errors.go b/app/controlplane/internal/biz/errors.go index f744511df..3094ecf71 100644 --- a/app/controlplane/internal/biz/errors.go +++ b/app/controlplane/internal/biz/errors.go @@ -56,6 +56,10 @@ type ErrValidation struct { err error } +func NewErrValidationStr(errMsg string) ErrValidation { + return ErrValidation{errors.New(errMsg)} +} + func NewErrValidation(err error) ErrValidation { return ErrValidation{err} } @@ -72,6 +76,10 @@ type ErrUnauthorized struct { err error } +func NewErrUnauthorizedStr(errMsg string) ErrUnauthorized { + return ErrUnauthorized{errors.New(errMsg)} +} + func NewErrUnauthorized(err error) ErrUnauthorized { return ErrUnauthorized{err} } diff --git a/app/controlplane/internal/biz/membership.go b/app/controlplane/internal/biz/membership.go index 7ef3eac73..673ce2b51 100644 --- a/app/controlplane/internal/biz/membership.go +++ b/app/controlplane/internal/biz/membership.go @@ -25,6 +25,7 @@ import ( type Membership struct { ID, UserID, OrganizationID uuid.UUID + UserEmail string Current bool CreatedAt, UpdatedAt *time.Time Org *Organization diff --git a/app/controlplane/internal/biz/orginvitation.go b/app/controlplane/internal/biz/orginvitation.go new file mode 100644 index 000000000..73978025b --- /dev/null +++ b/app/controlplane/internal/biz/orginvitation.go @@ -0,0 +1,268 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package biz + +import ( + "context" + "fmt" + "time" + + "github.com/chainloop-dev/chainloop/internal/servicelogger" + "github.com/go-kratos/kratos/v2/log" + "github.com/google/uuid" +) + +type OrgInvitationUseCase struct { + logger *log.Helper + repo OrgInvitationRepo + mRepo MembershipRepo + userRepo UserRepo +} + +type OrgInvitation struct { + ID uuid.UUID + Org *Organization + Sender *User + ReceiverEmail string + CreatedAt *time.Time + Status OrgInvitationStatus +} + +type OrgInvitationRepo interface { + Create(ctx context.Context, orgID, senderID uuid.UUID, receiverEmail string) (*OrgInvitation, error) + FindByID(ctx context.Context, ID uuid.UUID) (*OrgInvitation, error) + PendingInvitation(ctx context.Context, orgID uuid.UUID, receiverEmail string) (*OrgInvitation, error) + PendingInvitations(ctx context.Context, receiverEmail string) ([]*OrgInvitation, error) + SoftDelete(ctx context.Context, id uuid.UUID) error + ListBySender(ctx context.Context, sender uuid.UUID) ([]*OrgInvitation, error) + ChangeStatus(ctx context.Context, ID uuid.UUID, status OrgInvitationStatus) error +} + +func NewOrgInvitationUseCase(r OrgInvitationRepo, mRepo MembershipRepo, uRepo UserRepo, l log.Logger) (*OrgInvitationUseCase, error) { + return &OrgInvitationUseCase{ + logger: servicelogger.ScopedHelper(l, "biz/orgInvitation"), + repo: r, mRepo: mRepo, userRepo: uRepo, + }, nil +} + +func (uc *OrgInvitationUseCase) Create(ctx context.Context, orgID, senderID, receiverEmail string) (*OrgInvitation, error) { + // 1 - Static Validation + if receiverEmail == "" { + return nil, NewErrValidationStr("receiver email is required") + } + + orgUUID, err := uuid.Parse(orgID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + senderUUID, err := uuid.Parse(senderID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + // 2 - the sender exists and it's not the same than the receiver of the invitation + sender, err := uc.userRepo.FindByID(ctx, senderUUID) + if err != nil { + return nil, fmt.Errorf("error finding sender %s: %w", senderUUID.String(), err) + } else if sender == nil { + return nil, NewErrNotFound("sender") + } + + if sender.Email == receiverEmail { + return nil, NewErrValidationStr("sender and receiver emails cannot be the same") + } + + // 3 - The receiver does not exist in the org already + memberships, err := uc.mRepo.FindByOrg(ctx, orgUUID) + if err != nil { + return nil, fmt.Errorf("error finding memberships for user %s: %w", senderUUID.String(), err) + } + + for _, m := range memberships { + if m.UserEmail == receiverEmail { + return nil, NewErrValidationStr("user already exists in the org") + } + } + + // 4 - Check if the user has permissions to invite to the org + memberships, err = uc.mRepo.FindByUser(ctx, senderUUID) + if err != nil { + return nil, fmt.Errorf("error finding memberships for user %s: %w", senderUUID.String(), err) + } + + var hasPermission bool + for _, m := range memberships { + if m.OrganizationID == orgUUID { + // User has permission to invite to this org + hasPermission = true + break + } + } + + if !hasPermission { + return nil, NewErrNotFound("user does not have permission to invite to this org") + } + + // 5 - Check if there is already an invitation for this user for this org + m, err := uc.repo.PendingInvitation(ctx, orgUUID, receiverEmail) + if err != nil { + return nil, fmt.Errorf("error finding invitation for org %s and receiver %s: %w", orgID, receiverEmail, err) + } + + if m != nil { + return nil, NewErrValidationStr("invitation already exists for this user and org") + } + + // 5 - Create the invitation + invitation, err := uc.repo.Create(ctx, orgUUID, senderUUID, receiverEmail) + if err != nil { + return nil, fmt.Errorf("error creating invitation: %w", err) + } + + return invitation, nil +} + +func (uc *OrgInvitationUseCase) ListBySender(ctx context.Context, senderID string) ([]*OrgInvitation, error) { + senderUUID, err := uuid.Parse(senderID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + return uc.repo.ListBySender(ctx, senderUUID) +} + +// Revoke an invitation by ID only if the user is the one who created it +func (uc *OrgInvitationUseCase) Revoke(ctx context.Context, senderID, invitationID string) error { + invitationUUID, err := uuid.Parse(invitationID) + if err != nil { + return NewErrInvalidUUID(err) + } + + // We care only about invitations that are pending and sent by the user + m, err := uc.repo.FindByID(ctx, invitationUUID) + if err != nil { + return fmt.Errorf("error finding invitation %s: %w", invitationID, err) + } else if m == nil || m.Sender.ID != senderID { + return NewErrNotFound("invitation") + } + + if m.Status != OrgInvitationStatusPending { + return NewErrValidationStr("invitation is not in pending state") + } + + return uc.repo.SoftDelete(ctx, invitationUUID) +} + +// AcceptPendingInvitations accepts all pending invitations for a given user email +func (uc *OrgInvitationUseCase) AcceptPendingInvitations(ctx context.Context, receiverEmail string) error { + user, err := uc.userRepo.FindByEmail(ctx, receiverEmail) + if err != nil { + return fmt.Errorf("error finding user %s: %w", receiverEmail, err) + } else if user == nil { + return NewErrNotFound("user") + } + + userUUID, err := uuid.Parse(user.ID) + if err != nil { + return NewErrInvalidUUID(err) + } + + // Find all memberships for the user and all pending invitations + memberships, err := uc.mRepo.FindByUser(ctx, userUUID) + if err != nil { + return fmt.Errorf("error finding memberships for user %s: %w", receiverEmail, err) + } + + invitations, err := uc.repo.PendingInvitations(ctx, receiverEmail) + if err != nil { + return fmt.Errorf("error finding pending invitations for user %s: %w", receiverEmail, err) + } + + uc.logger.Infow("msg", "Checking pending invitations", "user_id", user.ID, "invitations", len(invitations)) + + // Iterate on the invitations and create the membership if it doesn't exist + for _, invitation := range invitations { + var alreadyMember bool + for _, m := range memberships { + if m.OrganizationID.String() == invitation.Org.ID { + alreadyMember = true + } + } + + orgUUID, err := uuid.Parse(invitation.Org.ID) + if err != nil { + return NewErrInvalidUUID(err) + } + + // user is not a member of the org, create the membership + if !alreadyMember { + uc.logger.Infow("msg", "Adding member", "invitation_id", invitation.ID.String(), "org_id", invitation.Org.ID, "user_id", user.ID) + if _, err := uc.mRepo.Create(ctx, orgUUID, userUUID, false); err != nil { + return fmt.Errorf("error creating membership for user %s: %w", receiverEmail, err) + } + } + + uc.logger.Infow("msg", "Accepting invitation", "invitation_id", invitation.ID.String(), "org_id", invitation.Org.ID, "user_id", user.ID) + // change the status of the invitation + if err := uc.repo.ChangeStatus(ctx, invitation.ID, OrgInvitationStatusAccepted); err != nil { + return fmt.Errorf("error changing status of invitation %s: %w", invitation.ID.String(), err) + } + } + + return nil +} + +func (uc *OrgInvitationUseCase) AcceptInvitation(ctx context.Context, invitationID string) error { + invitationUUID, err := uuid.Parse(invitationID) + if err != nil { + return NewErrInvalidUUID(err) + } + + return uc.repo.ChangeStatus(ctx, invitationUUID, OrgInvitationStatusAccepted) +} + +func (uc *OrgInvitationUseCase) FindByID(ctx context.Context, invitationID string) (*OrgInvitation, error) { + invitationUUID, err := uuid.Parse(invitationID) + if err != nil { + return nil, NewErrInvalidUUID(err) + } + + invitation, err := uc.repo.FindByID(ctx, invitationUUID) + if err != nil { + return nil, fmt.Errorf("error finding invitation %s: %w", invitationID, err) + } else if invitation == nil { + return nil, NewErrNotFound("invitation") + } + + return invitation, nil +} + +type OrgInvitationStatus string + +var ( + OrgInvitationStatusPending OrgInvitationStatus = "pending" + OrgInvitationStatusAccepted OrgInvitationStatus = "accepted" +) + +// Implements https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues +func (OrgInvitationStatus) Values() (kinds []string) { + for _, s := range []OrgInvitationStatus{OrgInvitationStatusAccepted, OrgInvitationStatusPending} { + kinds = append(kinds, string(s)) + } + + return +} diff --git a/app/controlplane/internal/biz/orginvitation_integration_test.go b/app/controlplane/internal/biz/orginvitation_integration_test.go new file mode 100644 index 000000000..801685ad1 --- /dev/null +++ b/app/controlplane/internal/biz/orginvitation_integration_test.go @@ -0,0 +1,235 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package biz_test + +import ( + "context" + "testing" + + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz/testhelpers" + "github.com/google/uuid" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +const receiverEmail = "sarah@cyberdyne.io" + +func (s *OrgInvitationIntegrationTestSuite) TestCreate() { + s.T().Run("invalid org ID", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), "deadbeef", s.user.ID, receiverEmail) + s.Error(err) + s.True(biz.IsErrInvalidUUID(err)) + s.Nil(invite) + }) + + s.T().Run("invalid user ID", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, "deadbeef", receiverEmail) + s.Error(err) + s.True(biz.IsErrInvalidUUID(err)) + s.Nil(invite) + }) + + s.T().Run("missing receiver email", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, "") + s.Error(err) + s.True(biz.IsErrValidation(err)) + s.Nil(invite) + }) + + s.T().Run("receiver email same than sender", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, s.user.Email) + s.Error(err) + s.ErrorContains(err, "sender and receiver emails cannot be the same") + s.True(biz.IsErrValidation(err)) + s.Nil(invite) + }) + + s.T().Run("receiver is already a member", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, s.user2.Email) + s.Error(err) + s.ErrorContains(err, "user already exists in the org") + s.True(biz.IsErrValidation(err)) + s.Nil(invite) + }) + + s.T().Run("org not found", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, uuid.NewString(), receiverEmail) + s.Error(err) + s.True(biz.IsNotFound(err)) + s.Nil(invite) + }) + + s.T().Run("user is not member of that org", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org3.ID, s.user.ID, receiverEmail) + s.Error(err) + s.True(biz.IsNotFound(err)) + s.Nil(invite) + }) + + s.T().Run("can create invites for org1 and 2", func(t *testing.T) { + for _, org := range []*biz.Organization{s.org1, s.org2} { + invite, err := s.OrgInvitation.Create(context.Background(), org.ID, s.user.ID, receiverEmail) + s.NoError(err) + s.Equal(org, invite.Org) + s.Equal(s.user, invite.Sender) + s.Equal(receiverEmail, invite.ReceiverEmail) + s.Equal(biz.OrgInvitationStatusPending, invite.Status) + s.NotNil(invite.CreatedAt) + } + }) + + s.T().Run("but can't create if there is one pending", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, receiverEmail) + s.Error(err) + s.ErrorContains(err, "already exists") + s.True(biz.IsErrValidation(err)) + s.Nil(invite) + }) + + s.T().Run("but it can if it's another email", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, "anotheremail@cyberdyne.io") + s.Equal("anotheremail@cyberdyne.io", invite.ReceiverEmail) + s.Equal(s.org1, invite.Org) + s.NoError(err) + }) +} + +func (s *OrgInvitationIntegrationTestSuite) TestAcceptPendingInvitations() { + ctx := context.Background() + receiver, err := s.User.FindOrCreateByEmail(ctx, receiverEmail) + require.NoError(s.T(), err) + + s.T().Run("user doesn't exist", func(t *testing.T) { + err := s.OrgInvitation.AcceptPendingInvitations(ctx, "non-existant@cyberdyne.io") + s.ErrorContains(err, "not found") + }) + + s.T().Run("no invites for user", func(t *testing.T) { + err = s.OrgInvitation.AcceptPendingInvitations(ctx, receiverEmail) + s.NoError(err) + + memberships, err := s.Membership.ByUser(ctx, receiver.ID) + s.NoError(err) + s.Len(memberships, 0) + }) + + s.T().Run("user is invited to org 1", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(ctx, s.org1.ID, s.user.ID, receiverEmail) + require.NoError(s.T(), err) + err = s.OrgInvitation.AcceptPendingInvitations(ctx, receiverEmail) + s.NoError(err) + + memberships, err := s.Membership.ByUser(ctx, receiver.ID) + s.NoError(err) + s.Len(memberships, 1) + assert.Equal(s.T(), s.org1.ID, memberships[0].OrganizationID.String()) + + // the invite is now accepted + invite, err = s.OrgInvitation.FindByID(ctx, invite.ID.String()) + s.NoError(err) + s.Equal(biz.OrgInvitationStatusAccepted, invite.Status) + }) +} + +func (s *OrgInvitationIntegrationTestSuite) TestRevoke() { + s.T().Run("invalid ID", func(t *testing.T) { + err := s.OrgInvitation.Revoke(context.Background(), s.user.ID, "deadbeef") + s.Error(err) + s.True(biz.IsErrInvalidUUID(err)) + }) + + s.T().Run("invitation not found", func(t *testing.T) { + err := s.OrgInvitation.Revoke(context.Background(), s.user.ID, uuid.NewString()) + s.Error(err) + s.True(biz.IsNotFound(err)) + }) + + s.T().Run("invitation not created by this user", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user2.ID, "anotheremail@cyberdyne.io") + require.NoError(s.T(), err) + err = s.OrgInvitation.Revoke(context.Background(), s.user.ID, invite.ID.String()) + s.Error(err) + s.True(biz.IsNotFound(err)) + }) + + s.T().Run("invitation not in pending state", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, receiverEmail) + require.NoError(s.T(), err) + err = s.OrgInvitation.AcceptInvitation(context.Background(), invite.ID.String()) + require.NoError(s.T(), err) + + // It's in accepted state now + err = s.OrgInvitation.Revoke(context.Background(), s.user.ID, invite.ID.String()) + s.Error(err) + s.ErrorContains(err, "not in pending state") + s.True(biz.IsErrValidation(err)) + }) + + s.T().Run("happy path", func(t *testing.T) { + invite, err := s.OrgInvitation.Create(context.Background(), s.org1.ID, s.user.ID, receiverEmail) + require.NoError(s.T(), err) + err = s.OrgInvitation.Revoke(context.Background(), s.user.ID, invite.ID.String()) + s.NoError(err) + err = s.OrgInvitation.Revoke(context.Background(), s.user.ID, invite.ID.String()) + s.Error(err) + s.True(biz.IsNotFound(err)) + }) +} + +// Run the tests +func TestOrgInvitationUseCase(t *testing.T) { + suite.Run(t, new(OrgInvitationIntegrationTestSuite)) +} + +// Utility struct to hold the test suite +type OrgInvitationIntegrationTestSuite struct { + testhelpers.UseCasesEachTestSuite + org1, org2, org3 *biz.Organization + user, user2 *biz.User +} + +// 3 orgs, user belongs to org1 and org2 but not org3 +func (s *OrgInvitationIntegrationTestSuite) SetupTest() { + t := s.T() + var err error + assert := assert.New(s.T()) + ctx := context.Background() + + s.TestingUseCases = testhelpers.NewTestingUseCases(t) + s.org1, err = s.Organization.Create(ctx, "org1") + assert.NoError(err) + s.org2, err = s.Organization.Create(ctx, "org2") + assert.NoError(err) + s.org3, err = s.Organization.Create(ctx, "org3") + assert.NoError(err) + + // Create User 1 + s.user, err = s.User.FindOrCreateByEmail(ctx, "user-1@test.com") + assert.NoError(err) + // Attach both orgs + _, err = s.Membership.Create(ctx, s.org1.ID, s.user.ID, true) + assert.NoError(err) + _, err = s.Membership.Create(ctx, s.org2.ID, s.user.ID, true) + assert.NoError(err) + + s.user2, err = s.User.FindOrCreateByEmail(ctx, "user-2@test.com") + assert.NoError(err) + _, err = s.Membership.Create(ctx, s.org1.ID, s.user2.ID, true) + assert.NoError(err) +} diff --git a/app/controlplane/internal/biz/testhelpers/database.go b/app/controlplane/internal/biz/testhelpers/database.go index c8d3776df..0ea1e40a9 100644 --- a/app/controlplane/internal/biz/testhelpers/database.go +++ b/app/controlplane/internal/biz/testhelpers/database.go @@ -64,6 +64,7 @@ type TestingUseCases struct { RobotAccount *biz.RobotAccountUseCase RegisteredIntegrations sdk.AvailablePlugins CASMapping *biz.CASMappingUseCase + OrgInvitation *biz.OrgInvitationUseCase } type newTestingOpts struct { diff --git a/app/controlplane/internal/biz/testhelpers/wire_gen.go b/app/controlplane/internal/biz/testhelpers/wire_gen.go index 16b727a28..f18fbb176 100644 --- a/app/controlplane/internal/biz/testhelpers/wire_gen.go +++ b/app/controlplane/internal/biz/testhelpers/wire_gen.go @@ -69,6 +69,12 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r robotAccountUseCase := biz.NewRootAccountUseCase(robotAccountRepo, workflowRepo, auth, logger) casMappingRepo := data.NewCASMappingRepo(dataData, casBackendRepo, logger) casMappingUseCase := biz.NewCASMappingUseCase(casMappingRepo, membershipRepo, logger) + orgInvitationRepo := data.NewOrgInvitation(dataData, logger) + orgInvitationUseCase, err := biz.NewOrgInvitationUseCase(orgInvitationRepo, membershipRepo, userRepo, logger) + if err != nil { + cleanup() + return nil, nil, err + } testingUseCases := &TestingUseCases{ DB: testDatabase, Data: dataData, @@ -84,6 +90,7 @@ func WireTestData(testDatabase *TestDatabase, t *testing.T, logger log.Logger, r RobotAccount: robotAccountUseCase, RegisteredIntegrations: availablePlugins, CASMapping: casMappingUseCase, + OrgInvitation: orgInvitationUseCase, } return testingUseCases, func() { cleanup() diff --git a/app/controlplane/internal/data/data.go b/app/controlplane/internal/data/data.go index cf57bffc3..ab3bd3d50 100644 --- a/app/controlplane/internal/data/data.go +++ b/app/controlplane/internal/data/data.go @@ -52,6 +52,7 @@ var ProviderSet = wire.NewSet( NewIntegrationAttachmentRepo, NewCASMappingRepo, NewMembershipRepo, + NewOrgInvitation, ) // Data . diff --git a/app/controlplane/internal/data/ent/client.go b/app/controlplane/internal/data/ent/client.go index a2d00bf04..dcf307000 100644 --- a/app/controlplane/internal/data/ent/client.go +++ b/app/controlplane/internal/data/ent/client.go @@ -21,6 +21,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/integrationattachment" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/membership" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/robotaccount" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/workflow" @@ -44,6 +45,8 @@ type Client struct { IntegrationAttachment *IntegrationAttachmentClient // Membership is the client for interacting with the Membership builders. Membership *MembershipClient + // OrgInvitation is the client for interacting with the OrgInvitation builders. + OrgInvitation *OrgInvitationClient // Organization is the client for interacting with the Organization builders. Organization *OrganizationClient // RobotAccount is the client for interacting with the RobotAccount builders. @@ -76,6 +79,7 @@ func (c *Client) init() { c.Integration = NewIntegrationClient(c.config) c.IntegrationAttachment = NewIntegrationAttachmentClient(c.config) c.Membership = NewMembershipClient(c.config) + c.OrgInvitation = NewOrgInvitationClient(c.config) c.Organization = NewOrganizationClient(c.config) c.RobotAccount = NewRobotAccountClient(c.config) c.User = NewUserClient(c.config) @@ -170,6 +174,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Integration: NewIntegrationClient(cfg), IntegrationAttachment: NewIntegrationAttachmentClient(cfg), Membership: NewMembershipClient(cfg), + OrgInvitation: NewOrgInvitationClient(cfg), Organization: NewOrganizationClient(cfg), RobotAccount: NewRobotAccountClient(cfg), User: NewUserClient(cfg), @@ -201,6 +206,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Integration: NewIntegrationClient(cfg), IntegrationAttachment: NewIntegrationAttachmentClient(cfg), Membership: NewMembershipClient(cfg), + OrgInvitation: NewOrgInvitationClient(cfg), Organization: NewOrganizationClient(cfg), RobotAccount: NewRobotAccountClient(cfg), User: NewUserClient(cfg), @@ -238,8 +244,8 @@ func (c *Client) Close() error { func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ c.CASBackend, c.CASMapping, c.Integration, c.IntegrationAttachment, - c.Membership, c.Organization, c.RobotAccount, c.User, c.Workflow, - c.WorkflowContract, c.WorkflowContractVersion, c.WorkflowRun, + c.Membership, c.OrgInvitation, c.Organization, c.RobotAccount, c.User, + c.Workflow, c.WorkflowContract, c.WorkflowContractVersion, c.WorkflowRun, } { n.Use(hooks...) } @@ -250,8 +256,8 @@ func (c *Client) Use(hooks ...Hook) { func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ c.CASBackend, c.CASMapping, c.Integration, c.IntegrationAttachment, - c.Membership, c.Organization, c.RobotAccount, c.User, c.Workflow, - c.WorkflowContract, c.WorkflowContractVersion, c.WorkflowRun, + c.Membership, c.OrgInvitation, c.Organization, c.RobotAccount, c.User, + c.Workflow, c.WorkflowContract, c.WorkflowContractVersion, c.WorkflowRun, } { n.Intercept(interceptors...) } @@ -270,6 +276,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.IntegrationAttachment.mutate(ctx, m) case *MembershipMutation: return c.Membership.mutate(ctx, m) + case *OrgInvitationMutation: + return c.OrgInvitation.mutate(ctx, m) case *OrganizationMutation: return c.Organization.mutate(ctx, m) case *RobotAccountMutation: @@ -1055,6 +1063,156 @@ func (c *MembershipClient) mutate(ctx context.Context, m *MembershipMutation) (V } } +// OrgInvitationClient is a client for the OrgInvitation schema. +type OrgInvitationClient struct { + config +} + +// NewOrgInvitationClient returns a client for the OrgInvitation from the given config. +func NewOrgInvitationClient(c config) *OrgInvitationClient { + return &OrgInvitationClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `orginvitation.Hooks(f(g(h())))`. +func (c *OrgInvitationClient) Use(hooks ...Hook) { + c.hooks.OrgInvitation = append(c.hooks.OrgInvitation, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `orginvitation.Intercept(f(g(h())))`. +func (c *OrgInvitationClient) Intercept(interceptors ...Interceptor) { + c.inters.OrgInvitation = append(c.inters.OrgInvitation, interceptors...) +} + +// Create returns a builder for creating a OrgInvitation entity. +func (c *OrgInvitationClient) Create() *OrgInvitationCreate { + mutation := newOrgInvitationMutation(c.config, OpCreate) + return &OrgInvitationCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of OrgInvitation entities. +func (c *OrgInvitationClient) CreateBulk(builders ...*OrgInvitationCreate) *OrgInvitationCreateBulk { + return &OrgInvitationCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for OrgInvitation. +func (c *OrgInvitationClient) Update() *OrgInvitationUpdate { + mutation := newOrgInvitationMutation(c.config, OpUpdate) + return &OrgInvitationUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *OrgInvitationClient) UpdateOne(oi *OrgInvitation) *OrgInvitationUpdateOne { + mutation := newOrgInvitationMutation(c.config, OpUpdateOne, withOrgInvitation(oi)) + return &OrgInvitationUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *OrgInvitationClient) UpdateOneID(id uuid.UUID) *OrgInvitationUpdateOne { + mutation := newOrgInvitationMutation(c.config, OpUpdateOne, withOrgInvitationID(id)) + return &OrgInvitationUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for OrgInvitation. +func (c *OrgInvitationClient) Delete() *OrgInvitationDelete { + mutation := newOrgInvitationMutation(c.config, OpDelete) + return &OrgInvitationDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *OrgInvitationClient) DeleteOne(oi *OrgInvitation) *OrgInvitationDeleteOne { + return c.DeleteOneID(oi.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *OrgInvitationClient) DeleteOneID(id uuid.UUID) *OrgInvitationDeleteOne { + builder := c.Delete().Where(orginvitation.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &OrgInvitationDeleteOne{builder} +} + +// Query returns a query builder for OrgInvitation. +func (c *OrgInvitationClient) Query() *OrgInvitationQuery { + return &OrgInvitationQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeOrgInvitation}, + inters: c.Interceptors(), + } +} + +// Get returns a OrgInvitation entity by its id. +func (c *OrgInvitationClient) Get(ctx context.Context, id uuid.UUID) (*OrgInvitation, error) { + return c.Query().Where(orginvitation.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *OrgInvitationClient) GetX(ctx context.Context, id uuid.UUID) *OrgInvitation { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryOrganization queries the organization edge of a OrgInvitation. +func (c *OrgInvitationClient) QueryOrganization(oi *OrgInvitation) *OrganizationQuery { + query := (&OrganizationClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := oi.ID + step := sqlgraph.NewStep( + sqlgraph.From(orginvitation.Table, orginvitation.FieldID, id), + sqlgraph.To(organization.Table, organization.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, orginvitation.OrganizationTable, orginvitation.OrganizationColumn), + ) + fromV = sqlgraph.Neighbors(oi.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QuerySender queries the sender edge of a OrgInvitation. +func (c *OrgInvitationClient) QuerySender(oi *OrgInvitation) *UserQuery { + query := (&UserClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := oi.ID + step := sqlgraph.NewStep( + sqlgraph.From(orginvitation.Table, orginvitation.FieldID, id), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, orginvitation.SenderTable, orginvitation.SenderColumn), + ) + fromV = sqlgraph.Neighbors(oi.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *OrgInvitationClient) Hooks() []Hook { + return c.hooks.OrgInvitation +} + +// Interceptors returns the client interceptors. +func (c *OrgInvitationClient) Interceptors() []Interceptor { + return c.inters.OrgInvitation +} + +func (c *OrgInvitationClient) mutate(ctx context.Context, m *OrgInvitationMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&OrgInvitationCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&OrgInvitationUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&OrgInvitationUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&OrgInvitationDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown OrgInvitation mutation op: %q", m.Op()) + } +} + // OrganizationClient is a client for the Organization schema. type OrganizationClient struct { config @@ -2221,12 +2379,12 @@ func (c *WorkflowRunClient) mutate(ctx context.Context, m *WorkflowRunMutation) type ( hooks struct { CASBackend, CASMapping, Integration, IntegrationAttachment, Membership, - Organization, RobotAccount, User, Workflow, WorkflowContract, + OrgInvitation, Organization, RobotAccount, User, Workflow, WorkflowContract, WorkflowContractVersion, WorkflowRun []ent.Hook } inters struct { CASBackend, CASMapping, Integration, IntegrationAttachment, Membership, - Organization, RobotAccount, User, Workflow, WorkflowContract, + OrgInvitation, Organization, RobotAccount, User, Workflow, WorkflowContract, WorkflowContractVersion, WorkflowRun []ent.Interceptor } ) diff --git a/app/controlplane/internal/data/ent/ent.go b/app/controlplane/internal/data/ent/ent.go index 20a13ce79..a7f277101 100644 --- a/app/controlplane/internal/data/ent/ent.go +++ b/app/controlplane/internal/data/ent/ent.go @@ -18,6 +18,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/integrationattachment" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/membership" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/robotaccount" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/workflow" @@ -89,6 +90,7 @@ func checkColumn(table, column string) error { integration.Table: integration.ValidColumn, integrationattachment.Table: integrationattachment.ValidColumn, membership.Table: membership.ValidColumn, + orginvitation.Table: orginvitation.ValidColumn, organization.Table: organization.ValidColumn, robotaccount.Table: robotaccount.ValidColumn, user.Table: user.ValidColumn, diff --git a/app/controlplane/internal/data/ent/hook/hook.go b/app/controlplane/internal/data/ent/hook/hook.go index 8c8ef2dc3..1fd7fcc45 100644 --- a/app/controlplane/internal/data/ent/hook/hook.go +++ b/app/controlplane/internal/data/ent/hook/hook.go @@ -69,6 +69,18 @@ func (f MembershipFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MembershipMutation", m) } +// The OrgInvitationFunc type is an adapter to allow the use of ordinary +// function as OrgInvitation mutator. +type OrgInvitationFunc func(context.Context, *ent.OrgInvitationMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f OrgInvitationFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.OrgInvitationMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.OrgInvitationMutation", m) +} + // The OrganizationFunc type is an adapter to allow the use of ordinary // function as Organization mutator. type OrganizationFunc func(context.Context, *ent.OrganizationMutation) (ent.Value, error) diff --git a/app/controlplane/internal/data/ent/migrate/migrations/20231031124431.sql b/app/controlplane/internal/data/ent/migrate/migrations/20231031124431.sql new file mode 100644 index 000000000..6099667fe --- /dev/null +++ b/app/controlplane/internal/data/ent/migrate/migrations/20231031124431.sql @@ -0,0 +1,2 @@ +-- Create "org_invitations" table +CREATE TABLE "org_invitations" ("id" uuid NOT NULL, "receiver_email" character varying NOT NULL, "status" character varying NOT NULL DEFAULT 'pending', "created_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, "deleted_at" timestamptz NULL, "organization_id" uuid NOT NULL, "sender_id" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "org_invitations_organizations_organization" FOREIGN KEY ("organization_id") REFERENCES "organizations" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT "org_invitations_users_sender" FOREIGN KEY ("sender_id") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION); diff --git a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum index 455600922..1c769d4b2 100644 --- a/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/internal/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:G+LKYj/Bqo1YsBY1/Rx0Qp1OHPzxKuyGFO7hTRXKpVo= +h1:umLlSIQCvc7uyWfzCSY6x/ZzSF4Bm5/ahIM7HN5y1b8= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -9,3 +9,4 @@ h1:G+LKYj/Bqo1YsBY1/Rx0Qp1OHPzxKuyGFO7hTRXKpVo= 20230904210324.sql h1:oF5XG1s8WxAwDrdS+36J3Ygkx1vj++d1xpJCtPxTFs4= 20230905084357.sql h1:VNLRcY8vRDq5WoHv6JqBMr8HCkxLxr0LFWQzvqVRTYk= 20230914221336.sql h1:MCsBIxQ6Ow1BEhCNEF0QfAkUJxPSPxJ4l5DyAOuKLlc= +20231031124431.sql h1:HxWLbK4otq1uvGWKqngAHcOL+8G+qHbFnhRfLZCboBQ= diff --git a/app/controlplane/internal/data/ent/migrate/schema.go b/app/controlplane/internal/data/ent/migrate/schema.go index 90209dc55..6fae33bd9 100644 --- a/app/controlplane/internal/data/ent/migrate/schema.go +++ b/app/controlplane/internal/data/ent/migrate/schema.go @@ -169,6 +169,36 @@ var ( }, }, } + // OrgInvitationsColumns holds the columns for the "org_invitations" table. + OrgInvitationsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeUUID, Unique: true}, + {Name: "receiver_email", Type: field.TypeString}, + {Name: "status", Type: field.TypeEnum, Enums: []string{"accepted", "pending"}, Default: "pending"}, + {Name: "created_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, + {Name: "deleted_at", Type: field.TypeTime, Nullable: true}, + {Name: "organization_id", Type: field.TypeUUID}, + {Name: "sender_id", Type: field.TypeUUID}, + } + // OrgInvitationsTable holds the schema information for the "org_invitations" table. + OrgInvitationsTable = &schema.Table{ + Name: "org_invitations", + Columns: OrgInvitationsColumns, + PrimaryKey: []*schema.Column{OrgInvitationsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "org_invitations_organizations_organization", + Columns: []*schema.Column{OrgInvitationsColumns[5]}, + RefColumns: []*schema.Column{OrganizationsColumns[0]}, + OnDelete: schema.NoAction, + }, + { + Symbol: "org_invitations_users_sender", + Columns: []*schema.Column{OrgInvitationsColumns[6]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + } // OrganizationsColumns holds the columns for the "organizations" table. OrganizationsColumns = []*schema.Column{ {Name: "id", Type: field.TypeUUID, Unique: true}, @@ -382,6 +412,7 @@ var ( IntegrationsTable, IntegrationAttachmentsTable, MembershipsTable, + OrgInvitationsTable, OrganizationsTable, RobotAccountsTable, UsersTable, @@ -403,6 +434,8 @@ func init() { IntegrationAttachmentsTable.ForeignKeys[1].RefTable = WorkflowsTable MembershipsTable.ForeignKeys[0].RefTable = OrganizationsTable MembershipsTable.ForeignKeys[1].RefTable = UsersTable + OrgInvitationsTable.ForeignKeys[0].RefTable = OrganizationsTable + OrgInvitationsTable.ForeignKeys[1].RefTable = UsersTable RobotAccountsTable.ForeignKeys[0].RefTable = WorkflowsTable WorkflowsTable.ForeignKeys[0].RefTable = OrganizationsTable WorkflowsTable.ForeignKeys[1].RefTable = WorkflowContractsTable diff --git a/app/controlplane/internal/data/ent/mutation.go b/app/controlplane/internal/data/ent/mutation.go index 535f78607..b0930fbe2 100644 --- a/app/controlplane/internal/data/ent/mutation.go +++ b/app/controlplane/internal/data/ent/mutation.go @@ -18,6 +18,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/integrationattachment" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/membership" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/predicate" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/robotaccount" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" @@ -43,6 +44,7 @@ const ( TypeIntegration = "Integration" TypeIntegrationAttachment = "IntegrationAttachment" TypeMembership = "Membership" + TypeOrgInvitation = "OrgInvitation" TypeOrganization = "Organization" TypeRobotAccount = "RobotAccount" TypeUser = "User" @@ -3621,6 +3623,728 @@ func (m *MembershipMutation) ResetEdge(name string) error { return fmt.Errorf("unknown Membership edge %s", name) } +// OrgInvitationMutation represents an operation that mutates the OrgInvitation nodes in the graph. +type OrgInvitationMutation struct { + config + op Op + typ string + id *uuid.UUID + receiver_email *string + status *biz.OrgInvitationStatus + created_at *time.Time + deleted_at *time.Time + clearedFields map[string]struct{} + organization *uuid.UUID + clearedorganization bool + sender *uuid.UUID + clearedsender bool + done bool + oldValue func(context.Context) (*OrgInvitation, error) + predicates []predicate.OrgInvitation +} + +var _ ent.Mutation = (*OrgInvitationMutation)(nil) + +// orginvitationOption allows management of the mutation configuration using functional options. +type orginvitationOption func(*OrgInvitationMutation) + +// newOrgInvitationMutation creates new mutation for the OrgInvitation entity. +func newOrgInvitationMutation(c config, op Op, opts ...orginvitationOption) *OrgInvitationMutation { + m := &OrgInvitationMutation{ + config: c, + op: op, + typ: TypeOrgInvitation, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withOrgInvitationID sets the ID field of the mutation. +func withOrgInvitationID(id uuid.UUID) orginvitationOption { + return func(m *OrgInvitationMutation) { + var ( + err error + once sync.Once + value *OrgInvitation + ) + m.oldValue = func(ctx context.Context) (*OrgInvitation, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().OrgInvitation.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withOrgInvitation sets the old OrgInvitation of the mutation. +func withOrgInvitation(node *OrgInvitation) orginvitationOption { + return func(m *OrgInvitationMutation) { + m.oldValue = func(context.Context) (*OrgInvitation, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m OrgInvitationMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m OrgInvitationMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of OrgInvitation entities. +func (m *OrgInvitationMutation) SetID(id uuid.UUID) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *OrgInvitationMutation) ID() (id uuid.UUID, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *OrgInvitationMutation) IDs(ctx context.Context) ([]uuid.UUID, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []uuid.UUID{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().OrgInvitation.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetReceiverEmail sets the "receiver_email" field. +func (m *OrgInvitationMutation) SetReceiverEmail(s string) { + m.receiver_email = &s +} + +// ReceiverEmail returns the value of the "receiver_email" field in the mutation. +func (m *OrgInvitationMutation) ReceiverEmail() (r string, exists bool) { + v := m.receiver_email + if v == nil { + return + } + return *v, true +} + +// OldReceiverEmail returns the old "receiver_email" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldReceiverEmail(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldReceiverEmail is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldReceiverEmail requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldReceiverEmail: %w", err) + } + return oldValue.ReceiverEmail, nil +} + +// ResetReceiverEmail resets all changes to the "receiver_email" field. +func (m *OrgInvitationMutation) ResetReceiverEmail() { + m.receiver_email = nil +} + +// SetStatus sets the "status" field. +func (m *OrgInvitationMutation) SetStatus(bis biz.OrgInvitationStatus) { + m.status = &bis +} + +// Status returns the value of the "status" field in the mutation. +func (m *OrgInvitationMutation) Status() (r biz.OrgInvitationStatus, exists bool) { + v := m.status + if v == nil { + return + } + return *v, true +} + +// OldStatus returns the old "status" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldStatus(ctx context.Context) (v biz.OrgInvitationStatus, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStatus is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStatus requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStatus: %w", err) + } + return oldValue.Status, nil +} + +// ResetStatus resets all changes to the "status" field. +func (m *OrgInvitationMutation) ResetStatus() { + m.status = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *OrgInvitationMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *OrgInvitationMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *OrgInvitationMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetDeletedAt sets the "deleted_at" field. +func (m *OrgInvitationMutation) SetDeletedAt(t time.Time) { + m.deleted_at = &t +} + +// DeletedAt returns the value of the "deleted_at" field in the mutation. +func (m *OrgInvitationMutation) DeletedAt() (r time.Time, exists bool) { + v := m.deleted_at + if v == nil { + return + } + return *v, true +} + +// OldDeletedAt returns the old "deleted_at" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldDeletedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDeletedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err) + } + return oldValue.DeletedAt, nil +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (m *OrgInvitationMutation) ClearDeletedAt() { + m.deleted_at = nil + m.clearedFields[orginvitation.FieldDeletedAt] = struct{}{} +} + +// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation. +func (m *OrgInvitationMutation) DeletedAtCleared() bool { + _, ok := m.clearedFields[orginvitation.FieldDeletedAt] + return ok +} + +// ResetDeletedAt resets all changes to the "deleted_at" field. +func (m *OrgInvitationMutation) ResetDeletedAt() { + m.deleted_at = nil + delete(m.clearedFields, orginvitation.FieldDeletedAt) +} + +// SetOrganizationID sets the "organization_id" field. +func (m *OrgInvitationMutation) SetOrganizationID(u uuid.UUID) { + m.organization = &u +} + +// OrganizationID returns the value of the "organization_id" field in the mutation. +func (m *OrgInvitationMutation) OrganizationID() (r uuid.UUID, exists bool) { + v := m.organization + if v == nil { + return + } + return *v, true +} + +// OldOrganizationID returns the old "organization_id" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldOrganizationID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOrganizationID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOrganizationID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOrganizationID: %w", err) + } + return oldValue.OrganizationID, nil +} + +// ResetOrganizationID resets all changes to the "organization_id" field. +func (m *OrgInvitationMutation) ResetOrganizationID() { + m.organization = nil +} + +// SetSenderID sets the "sender_id" field. +func (m *OrgInvitationMutation) SetSenderID(u uuid.UUID) { + m.sender = &u +} + +// SenderID returns the value of the "sender_id" field in the mutation. +func (m *OrgInvitationMutation) SenderID() (r uuid.UUID, exists bool) { + v := m.sender + if v == nil { + return + } + return *v, true +} + +// OldSenderID returns the old "sender_id" field's value of the OrgInvitation entity. +// If the OrgInvitation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *OrgInvitationMutation) OldSenderID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSenderID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSenderID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSenderID: %w", err) + } + return oldValue.SenderID, nil +} + +// ResetSenderID resets all changes to the "sender_id" field. +func (m *OrgInvitationMutation) ResetSenderID() { + m.sender = nil +} + +// ClearOrganization clears the "organization" edge to the Organization entity. +func (m *OrgInvitationMutation) ClearOrganization() { + m.clearedorganization = true +} + +// OrganizationCleared reports if the "organization" edge to the Organization entity was cleared. +func (m *OrgInvitationMutation) OrganizationCleared() bool { + return m.clearedorganization +} + +// OrganizationIDs returns the "organization" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// OrganizationID instead. It exists only for internal usage by the builders. +func (m *OrgInvitationMutation) OrganizationIDs() (ids []uuid.UUID) { + if id := m.organization; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetOrganization resets all changes to the "organization" edge. +func (m *OrgInvitationMutation) ResetOrganization() { + m.organization = nil + m.clearedorganization = false +} + +// ClearSender clears the "sender" edge to the User entity. +func (m *OrgInvitationMutation) ClearSender() { + m.clearedsender = true +} + +// SenderCleared reports if the "sender" edge to the User entity was cleared. +func (m *OrgInvitationMutation) SenderCleared() bool { + return m.clearedsender +} + +// SenderIDs returns the "sender" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// SenderID instead. It exists only for internal usage by the builders. +func (m *OrgInvitationMutation) SenderIDs() (ids []uuid.UUID) { + if id := m.sender; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetSender resets all changes to the "sender" edge. +func (m *OrgInvitationMutation) ResetSender() { + m.sender = nil + m.clearedsender = false +} + +// Where appends a list predicates to the OrgInvitationMutation builder. +func (m *OrgInvitationMutation) Where(ps ...predicate.OrgInvitation) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the OrgInvitationMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *OrgInvitationMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.OrgInvitation, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *OrgInvitationMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *OrgInvitationMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (OrgInvitation). +func (m *OrgInvitationMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *OrgInvitationMutation) Fields() []string { + fields := make([]string, 0, 6) + if m.receiver_email != nil { + fields = append(fields, orginvitation.FieldReceiverEmail) + } + if m.status != nil { + fields = append(fields, orginvitation.FieldStatus) + } + if m.created_at != nil { + fields = append(fields, orginvitation.FieldCreatedAt) + } + if m.deleted_at != nil { + fields = append(fields, orginvitation.FieldDeletedAt) + } + if m.organization != nil { + fields = append(fields, orginvitation.FieldOrganizationID) + } + if m.sender != nil { + fields = append(fields, orginvitation.FieldSenderID) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *OrgInvitationMutation) Field(name string) (ent.Value, bool) { + switch name { + case orginvitation.FieldReceiverEmail: + return m.ReceiverEmail() + case orginvitation.FieldStatus: + return m.Status() + case orginvitation.FieldCreatedAt: + return m.CreatedAt() + case orginvitation.FieldDeletedAt: + return m.DeletedAt() + case orginvitation.FieldOrganizationID: + return m.OrganizationID() + case orginvitation.FieldSenderID: + return m.SenderID() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *OrgInvitationMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case orginvitation.FieldReceiverEmail: + return m.OldReceiverEmail(ctx) + case orginvitation.FieldStatus: + return m.OldStatus(ctx) + case orginvitation.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case orginvitation.FieldDeletedAt: + return m.OldDeletedAt(ctx) + case orginvitation.FieldOrganizationID: + return m.OldOrganizationID(ctx) + case orginvitation.FieldSenderID: + return m.OldSenderID(ctx) + } + return nil, fmt.Errorf("unknown OrgInvitation field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *OrgInvitationMutation) SetField(name string, value ent.Value) error { + switch name { + case orginvitation.FieldReceiverEmail: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetReceiverEmail(v) + return nil + case orginvitation.FieldStatus: + v, ok := value.(biz.OrgInvitationStatus) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStatus(v) + return nil + case orginvitation.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case orginvitation.FieldDeletedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDeletedAt(v) + return nil + case orginvitation.FieldOrganizationID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOrganizationID(v) + return nil + case orginvitation.FieldSenderID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSenderID(v) + return nil + } + return fmt.Errorf("unknown OrgInvitation field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *OrgInvitationMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *OrgInvitationMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *OrgInvitationMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown OrgInvitation numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *OrgInvitationMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(orginvitation.FieldDeletedAt) { + fields = append(fields, orginvitation.FieldDeletedAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *OrgInvitationMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *OrgInvitationMutation) ClearField(name string) error { + switch name { + case orginvitation.FieldDeletedAt: + m.ClearDeletedAt() + return nil + } + return fmt.Errorf("unknown OrgInvitation nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *OrgInvitationMutation) ResetField(name string) error { + switch name { + case orginvitation.FieldReceiverEmail: + m.ResetReceiverEmail() + return nil + case orginvitation.FieldStatus: + m.ResetStatus() + return nil + case orginvitation.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case orginvitation.FieldDeletedAt: + m.ResetDeletedAt() + return nil + case orginvitation.FieldOrganizationID: + m.ResetOrganizationID() + return nil + case orginvitation.FieldSenderID: + m.ResetSenderID() + return nil + } + return fmt.Errorf("unknown OrgInvitation field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *OrgInvitationMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.organization != nil { + edges = append(edges, orginvitation.EdgeOrganization) + } + if m.sender != nil { + edges = append(edges, orginvitation.EdgeSender) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *OrgInvitationMutation) AddedIDs(name string) []ent.Value { + switch name { + case orginvitation.EdgeOrganization: + if id := m.organization; id != nil { + return []ent.Value{*id} + } + case orginvitation.EdgeSender: + if id := m.sender; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *OrgInvitationMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *OrgInvitationMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *OrgInvitationMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.clearedorganization { + edges = append(edges, orginvitation.EdgeOrganization) + } + if m.clearedsender { + edges = append(edges, orginvitation.EdgeSender) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *OrgInvitationMutation) EdgeCleared(name string) bool { + switch name { + case orginvitation.EdgeOrganization: + return m.clearedorganization + case orginvitation.EdgeSender: + return m.clearedsender + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *OrgInvitationMutation) ClearEdge(name string) error { + switch name { + case orginvitation.EdgeOrganization: + m.ClearOrganization() + return nil + case orginvitation.EdgeSender: + m.ClearSender() + return nil + } + return fmt.Errorf("unknown OrgInvitation unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *OrgInvitationMutation) ResetEdge(name string) error { + switch name { + case orginvitation.EdgeOrganization: + m.ResetOrganization() + return nil + case orginvitation.EdgeSender: + m.ResetSender() + return nil + } + return fmt.Errorf("unknown OrgInvitation edge %s", name) +} + // OrganizationMutation represents an operation that mutates the Organization nodes in the graph. type OrganizationMutation struct { config diff --git a/app/controlplane/internal/data/ent/orginvitation.go b/app/controlplane/internal/data/ent/orginvitation.go new file mode 100644 index 000000000..a993c743f --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation.go @@ -0,0 +1,215 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" + "github.com/google/uuid" +) + +// OrgInvitation is the model entity for the OrgInvitation schema. +type OrgInvitation struct { + config `json:"-"` + // ID of the ent. + ID uuid.UUID `json:"id,omitempty"` + // ReceiverEmail holds the value of the "receiver_email" field. + ReceiverEmail string `json:"receiver_email,omitempty"` + // Status holds the value of the "status" field. + Status biz.OrgInvitationStatus `json:"status,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // DeletedAt holds the value of the "deleted_at" field. + DeletedAt time.Time `json:"deleted_at,omitempty"` + // OrganizationID holds the value of the "organization_id" field. + OrganizationID uuid.UUID `json:"organization_id,omitempty"` + // SenderID holds the value of the "sender_id" field. + SenderID uuid.UUID `json:"sender_id,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the OrgInvitationQuery when eager-loading is set. + Edges OrgInvitationEdges `json:"edges"` + selectValues sql.SelectValues +} + +// OrgInvitationEdges holds the relations/edges for other nodes in the graph. +type OrgInvitationEdges struct { + // Organization holds the value of the organization edge. + Organization *Organization `json:"organization,omitempty"` + // Sender holds the value of the sender edge. + Sender *User `json:"sender,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [2]bool +} + +// OrganizationOrErr returns the Organization value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e OrgInvitationEdges) OrganizationOrErr() (*Organization, error) { + if e.loadedTypes[0] { + if e.Organization == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: organization.Label} + } + return e.Organization, nil + } + return nil, &NotLoadedError{edge: "organization"} +} + +// SenderOrErr returns the Sender value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e OrgInvitationEdges) SenderOrErr() (*User, error) { + if e.loadedTypes[1] { + if e.Sender == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.Sender, nil + } + return nil, &NotLoadedError{edge: "sender"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*OrgInvitation) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case orginvitation.FieldReceiverEmail, orginvitation.FieldStatus: + values[i] = new(sql.NullString) + case orginvitation.FieldCreatedAt, orginvitation.FieldDeletedAt: + values[i] = new(sql.NullTime) + case orginvitation.FieldID, orginvitation.FieldOrganizationID, orginvitation.FieldSenderID: + values[i] = new(uuid.UUID) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the OrgInvitation fields. +func (oi *OrgInvitation) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case orginvitation.FieldID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value != nil { + oi.ID = *value + } + case orginvitation.FieldReceiverEmail: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field receiver_email", values[i]) + } else if value.Valid { + oi.ReceiverEmail = value.String + } + case orginvitation.FieldStatus: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field status", values[i]) + } else if value.Valid { + oi.Status = biz.OrgInvitationStatus(value.String) + } + case orginvitation.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + oi.CreatedAt = value.Time + } + case orginvitation.FieldDeletedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field deleted_at", values[i]) + } else if value.Valid { + oi.DeletedAt = value.Time + } + case orginvitation.FieldOrganizationID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field organization_id", values[i]) + } else if value != nil { + oi.OrganizationID = *value + } + case orginvitation.FieldSenderID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field sender_id", values[i]) + } else if value != nil { + oi.SenderID = *value + } + default: + oi.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the OrgInvitation. +// This includes values selected through modifiers, order, etc. +func (oi *OrgInvitation) Value(name string) (ent.Value, error) { + return oi.selectValues.Get(name) +} + +// QueryOrganization queries the "organization" edge of the OrgInvitation entity. +func (oi *OrgInvitation) QueryOrganization() *OrganizationQuery { + return NewOrgInvitationClient(oi.config).QueryOrganization(oi) +} + +// QuerySender queries the "sender" edge of the OrgInvitation entity. +func (oi *OrgInvitation) QuerySender() *UserQuery { + return NewOrgInvitationClient(oi.config).QuerySender(oi) +} + +// Update returns a builder for updating this OrgInvitation. +// Note that you need to call OrgInvitation.Unwrap() before calling this method if this OrgInvitation +// was returned from a transaction, and the transaction was committed or rolled back. +func (oi *OrgInvitation) Update() *OrgInvitationUpdateOne { + return NewOrgInvitationClient(oi.config).UpdateOne(oi) +} + +// Unwrap unwraps the OrgInvitation entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (oi *OrgInvitation) Unwrap() *OrgInvitation { + _tx, ok := oi.config.driver.(*txDriver) + if !ok { + panic("ent: OrgInvitation is not a transactional entity") + } + oi.config.driver = _tx.drv + return oi +} + +// String implements the fmt.Stringer. +func (oi *OrgInvitation) String() string { + var builder strings.Builder + builder.WriteString("OrgInvitation(") + builder.WriteString(fmt.Sprintf("id=%v, ", oi.ID)) + builder.WriteString("receiver_email=") + builder.WriteString(oi.ReceiverEmail) + builder.WriteString(", ") + builder.WriteString("status=") + builder.WriteString(fmt.Sprintf("%v", oi.Status)) + builder.WriteString(", ") + builder.WriteString("created_at=") + builder.WriteString(oi.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("deleted_at=") + builder.WriteString(oi.DeletedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("organization_id=") + builder.WriteString(fmt.Sprintf("%v", oi.OrganizationID)) + builder.WriteString(", ") + builder.WriteString("sender_id=") + builder.WriteString(fmt.Sprintf("%v", oi.SenderID)) + builder.WriteByte(')') + return builder.String() +} + +// OrgInvitations is a parsable slice of OrgInvitation. +type OrgInvitations []*OrgInvitation diff --git a/app/controlplane/internal/data/ent/orginvitation/orginvitation.go b/app/controlplane/internal/data/ent/orginvitation/orginvitation.go new file mode 100644 index 000000000..039b4fd70 --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation/orginvitation.go @@ -0,0 +1,158 @@ +// Code generated by ent, DO NOT EDIT. + +package orginvitation + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/google/uuid" +) + +const ( + // Label holds the string label denoting the orginvitation type in the database. + Label = "org_invitation" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldReceiverEmail holds the string denoting the receiver_email field in the database. + FieldReceiverEmail = "receiver_email" + // FieldStatus holds the string denoting the status field in the database. + FieldStatus = "status" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldDeletedAt holds the string denoting the deleted_at field in the database. + FieldDeletedAt = "deleted_at" + // FieldOrganizationID holds the string denoting the organization_id field in the database. + FieldOrganizationID = "organization_id" + // FieldSenderID holds the string denoting the sender_id field in the database. + FieldSenderID = "sender_id" + // EdgeOrganization holds the string denoting the organization edge name in mutations. + EdgeOrganization = "organization" + // EdgeSender holds the string denoting the sender edge name in mutations. + EdgeSender = "sender" + // Table holds the table name of the orginvitation in the database. + Table = "org_invitations" + // OrganizationTable is the table that holds the organization relation/edge. + OrganizationTable = "org_invitations" + // OrganizationInverseTable is the table name for the Organization entity. + // It exists in this package in order to avoid circular dependency with the "organization" package. + OrganizationInverseTable = "organizations" + // OrganizationColumn is the table column denoting the organization relation/edge. + OrganizationColumn = "organization_id" + // SenderTable is the table that holds the sender relation/edge. + SenderTable = "org_invitations" + // SenderInverseTable is the table name for the User entity. + // It exists in this package in order to avoid circular dependency with the "user" package. + SenderInverseTable = "users" + // SenderColumn is the table column denoting the sender relation/edge. + SenderColumn = "sender_id" +) + +// Columns holds all SQL columns for orginvitation fields. +var Columns = []string{ + FieldID, + FieldReceiverEmail, + FieldStatus, + FieldCreatedAt, + FieldDeletedAt, + FieldOrganizationID, + FieldSenderID, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() uuid.UUID +) + +const DefaultStatus biz.OrgInvitationStatus = "pending" + +// StatusValidator is a validator for the "status" field enum values. It is called by the builders before save. +func StatusValidator(s biz.OrgInvitationStatus) error { + switch s { + case "accepted", "pending": + return nil + default: + return fmt.Errorf("orginvitation: invalid enum value for status field: %q", s) + } +} + +// OrderOption defines the ordering options for the OrgInvitation queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByReceiverEmail orders the results by the receiver_email field. +func ByReceiverEmail(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldReceiverEmail, opts...).ToFunc() +} + +// ByStatus orders the results by the status field. +func ByStatus(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStatus, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByDeletedAt orders the results by the deleted_at field. +func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDeletedAt, opts...).ToFunc() +} + +// ByOrganizationID orders the results by the organization_id field. +func ByOrganizationID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldOrganizationID, opts...).ToFunc() +} + +// BySenderID orders the results by the sender_id field. +func BySenderID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldSenderID, opts...).ToFunc() +} + +// ByOrganizationField orders the results by organization field. +func ByOrganizationField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newOrganizationStep(), sql.OrderByField(field, opts...)) + } +} + +// BySenderField orders the results by sender field. +func BySenderField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newSenderStep(), sql.OrderByField(field, opts...)) + } +} +func newOrganizationStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(OrganizationInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, OrganizationTable, OrganizationColumn), + ) +} +func newSenderStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(SenderInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, SenderTable, SenderColumn), + ) +} diff --git a/app/controlplane/internal/data/ent/orginvitation/where.go b/app/controlplane/internal/data/ent/orginvitation/where.go new file mode 100644 index 000000000..ab2fa089b --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation/where.go @@ -0,0 +1,386 @@ +// Code generated by ent, DO NOT EDIT. + +package orginvitation + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/predicate" + "github.com/google/uuid" +) + +// ID filters vertices based on their ID field. +func ID(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLTE(FieldID, id)) +} + +// ReceiverEmail applies equality check predicate on the "receiver_email" field. It's identical to ReceiverEmailEQ. +func ReceiverEmail(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldReceiverEmail, v)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldCreatedAt, v)) +} + +// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ. +func DeletedAt(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldDeletedAt, v)) +} + +// OrganizationID applies equality check predicate on the "organization_id" field. It's identical to OrganizationIDEQ. +func OrganizationID(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldOrganizationID, v)) +} + +// SenderID applies equality check predicate on the "sender_id" field. It's identical to SenderIDEQ. +func SenderID(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldSenderID, v)) +} + +// ReceiverEmailEQ applies the EQ predicate on the "receiver_email" field. +func ReceiverEmailEQ(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldReceiverEmail, v)) +} + +// ReceiverEmailNEQ applies the NEQ predicate on the "receiver_email" field. +func ReceiverEmailNEQ(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldReceiverEmail, v)) +} + +// ReceiverEmailIn applies the In predicate on the "receiver_email" field. +func ReceiverEmailIn(vs ...string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldReceiverEmail, vs...)) +} + +// ReceiverEmailNotIn applies the NotIn predicate on the "receiver_email" field. +func ReceiverEmailNotIn(vs ...string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldReceiverEmail, vs...)) +} + +// ReceiverEmailGT applies the GT predicate on the "receiver_email" field. +func ReceiverEmailGT(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGT(FieldReceiverEmail, v)) +} + +// ReceiverEmailGTE applies the GTE predicate on the "receiver_email" field. +func ReceiverEmailGTE(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGTE(FieldReceiverEmail, v)) +} + +// ReceiverEmailLT applies the LT predicate on the "receiver_email" field. +func ReceiverEmailLT(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLT(FieldReceiverEmail, v)) +} + +// ReceiverEmailLTE applies the LTE predicate on the "receiver_email" field. +func ReceiverEmailLTE(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLTE(FieldReceiverEmail, v)) +} + +// ReceiverEmailContains applies the Contains predicate on the "receiver_email" field. +func ReceiverEmailContains(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldContains(FieldReceiverEmail, v)) +} + +// ReceiverEmailHasPrefix applies the HasPrefix predicate on the "receiver_email" field. +func ReceiverEmailHasPrefix(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldHasPrefix(FieldReceiverEmail, v)) +} + +// ReceiverEmailHasSuffix applies the HasSuffix predicate on the "receiver_email" field. +func ReceiverEmailHasSuffix(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldHasSuffix(FieldReceiverEmail, v)) +} + +// ReceiverEmailEqualFold applies the EqualFold predicate on the "receiver_email" field. +func ReceiverEmailEqualFold(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEqualFold(FieldReceiverEmail, v)) +} + +// ReceiverEmailContainsFold applies the ContainsFold predicate on the "receiver_email" field. +func ReceiverEmailContainsFold(v string) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldContainsFold(FieldReceiverEmail, v)) +} + +// StatusEQ applies the EQ predicate on the "status" field. +func StatusEQ(v biz.OrgInvitationStatus) predicate.OrgInvitation { + vc := v + return predicate.OrgInvitation(sql.FieldEQ(FieldStatus, vc)) +} + +// StatusNEQ applies the NEQ predicate on the "status" field. +func StatusNEQ(v biz.OrgInvitationStatus) predicate.OrgInvitation { + vc := v + return predicate.OrgInvitation(sql.FieldNEQ(FieldStatus, vc)) +} + +// StatusIn applies the In predicate on the "status" field. +func StatusIn(vs ...biz.OrgInvitationStatus) predicate.OrgInvitation { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.OrgInvitation(sql.FieldIn(FieldStatus, v...)) +} + +// StatusNotIn applies the NotIn predicate on the "status" field. +func StatusNotIn(vs ...biz.OrgInvitationStatus) predicate.OrgInvitation { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.OrgInvitation(sql.FieldNotIn(FieldStatus, v...)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLTE(FieldCreatedAt, v)) +} + +// DeletedAtEQ applies the EQ predicate on the "deleted_at" field. +func DeletedAtEQ(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldDeletedAt, v)) +} + +// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field. +func DeletedAtNEQ(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldDeletedAt, v)) +} + +// DeletedAtIn applies the In predicate on the "deleted_at" field. +func DeletedAtIn(vs ...time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldDeletedAt, vs...)) +} + +// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field. +func DeletedAtNotIn(vs ...time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldDeletedAt, vs...)) +} + +// DeletedAtGT applies the GT predicate on the "deleted_at" field. +func DeletedAtGT(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGT(FieldDeletedAt, v)) +} + +// DeletedAtGTE applies the GTE predicate on the "deleted_at" field. +func DeletedAtGTE(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldGTE(FieldDeletedAt, v)) +} + +// DeletedAtLT applies the LT predicate on the "deleted_at" field. +func DeletedAtLT(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLT(FieldDeletedAt, v)) +} + +// DeletedAtLTE applies the LTE predicate on the "deleted_at" field. +func DeletedAtLTE(v time.Time) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldLTE(FieldDeletedAt, v)) +} + +// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field. +func DeletedAtIsNil() predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIsNull(FieldDeletedAt)) +} + +// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field. +func DeletedAtNotNil() predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotNull(FieldDeletedAt)) +} + +// OrganizationIDEQ applies the EQ predicate on the "organization_id" field. +func OrganizationIDEQ(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldOrganizationID, v)) +} + +// OrganizationIDNEQ applies the NEQ predicate on the "organization_id" field. +func OrganizationIDNEQ(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldOrganizationID, v)) +} + +// OrganizationIDIn applies the In predicate on the "organization_id" field. +func OrganizationIDIn(vs ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldOrganizationID, vs...)) +} + +// OrganizationIDNotIn applies the NotIn predicate on the "organization_id" field. +func OrganizationIDNotIn(vs ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldOrganizationID, vs...)) +} + +// SenderIDEQ applies the EQ predicate on the "sender_id" field. +func SenderIDEQ(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldEQ(FieldSenderID, v)) +} + +// SenderIDNEQ applies the NEQ predicate on the "sender_id" field. +func SenderIDNEQ(v uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNEQ(FieldSenderID, v)) +} + +// SenderIDIn applies the In predicate on the "sender_id" field. +func SenderIDIn(vs ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldIn(FieldSenderID, vs...)) +} + +// SenderIDNotIn applies the NotIn predicate on the "sender_id" field. +func SenderIDNotIn(vs ...uuid.UUID) predicate.OrgInvitation { + return predicate.OrgInvitation(sql.FieldNotIn(FieldSenderID, vs...)) +} + +// HasOrganization applies the HasEdge predicate on the "organization" edge. +func HasOrganization() predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, OrganizationTable, OrganizationColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasOrganizationWith applies the HasEdge predicate on the "organization" edge with a given conditions (other predicates). +func HasOrganizationWith(preds ...predicate.Organization) predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + step := newOrganizationStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasSender applies the HasEdge predicate on the "sender" edge. +func HasSender() predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, SenderTable, SenderColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasSenderWith applies the HasEdge predicate on the "sender" edge with a given conditions (other predicates). +func HasSenderWith(preds ...predicate.User) predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + step := newSenderStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.OrgInvitation) predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.OrgInvitation) predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.OrgInvitation) predicate.OrgInvitation { + return predicate.OrgInvitation(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/app/controlplane/internal/data/ent/orginvitation_create.go b/app/controlplane/internal/data/ent/orginvitation_create.go new file mode 100644 index 000000000..0ed43307a --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation_create.go @@ -0,0 +1,354 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" + "github.com/google/uuid" +) + +// OrgInvitationCreate is the builder for creating a OrgInvitation entity. +type OrgInvitationCreate struct { + config + mutation *OrgInvitationMutation + hooks []Hook +} + +// SetReceiverEmail sets the "receiver_email" field. +func (oic *OrgInvitationCreate) SetReceiverEmail(s string) *OrgInvitationCreate { + oic.mutation.SetReceiverEmail(s) + return oic +} + +// SetStatus sets the "status" field. +func (oic *OrgInvitationCreate) SetStatus(bis biz.OrgInvitationStatus) *OrgInvitationCreate { + oic.mutation.SetStatus(bis) + return oic +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (oic *OrgInvitationCreate) SetNillableStatus(bis *biz.OrgInvitationStatus) *OrgInvitationCreate { + if bis != nil { + oic.SetStatus(*bis) + } + return oic +} + +// SetCreatedAt sets the "created_at" field. +func (oic *OrgInvitationCreate) SetCreatedAt(t time.Time) *OrgInvitationCreate { + oic.mutation.SetCreatedAt(t) + return oic +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (oic *OrgInvitationCreate) SetNillableCreatedAt(t *time.Time) *OrgInvitationCreate { + if t != nil { + oic.SetCreatedAt(*t) + } + return oic +} + +// SetDeletedAt sets the "deleted_at" field. +func (oic *OrgInvitationCreate) SetDeletedAt(t time.Time) *OrgInvitationCreate { + oic.mutation.SetDeletedAt(t) + return oic +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (oic *OrgInvitationCreate) SetNillableDeletedAt(t *time.Time) *OrgInvitationCreate { + if t != nil { + oic.SetDeletedAt(*t) + } + return oic +} + +// SetOrganizationID sets the "organization_id" field. +func (oic *OrgInvitationCreate) SetOrganizationID(u uuid.UUID) *OrgInvitationCreate { + oic.mutation.SetOrganizationID(u) + return oic +} + +// SetSenderID sets the "sender_id" field. +func (oic *OrgInvitationCreate) SetSenderID(u uuid.UUID) *OrgInvitationCreate { + oic.mutation.SetSenderID(u) + return oic +} + +// SetID sets the "id" field. +func (oic *OrgInvitationCreate) SetID(u uuid.UUID) *OrgInvitationCreate { + oic.mutation.SetID(u) + return oic +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (oic *OrgInvitationCreate) SetNillableID(u *uuid.UUID) *OrgInvitationCreate { + if u != nil { + oic.SetID(*u) + } + return oic +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (oic *OrgInvitationCreate) SetOrganization(o *Organization) *OrgInvitationCreate { + return oic.SetOrganizationID(o.ID) +} + +// SetSender sets the "sender" edge to the User entity. +func (oic *OrgInvitationCreate) SetSender(u *User) *OrgInvitationCreate { + return oic.SetSenderID(u.ID) +} + +// Mutation returns the OrgInvitationMutation object of the builder. +func (oic *OrgInvitationCreate) Mutation() *OrgInvitationMutation { + return oic.mutation +} + +// Save creates the OrgInvitation in the database. +func (oic *OrgInvitationCreate) Save(ctx context.Context) (*OrgInvitation, error) { + oic.defaults() + return withHooks(ctx, oic.sqlSave, oic.mutation, oic.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (oic *OrgInvitationCreate) SaveX(ctx context.Context) *OrgInvitation { + v, err := oic.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (oic *OrgInvitationCreate) Exec(ctx context.Context) error { + _, err := oic.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (oic *OrgInvitationCreate) ExecX(ctx context.Context) { + if err := oic.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (oic *OrgInvitationCreate) defaults() { + if _, ok := oic.mutation.Status(); !ok { + v := orginvitation.DefaultStatus + oic.mutation.SetStatus(v) + } + if _, ok := oic.mutation.CreatedAt(); !ok { + v := orginvitation.DefaultCreatedAt() + oic.mutation.SetCreatedAt(v) + } + if _, ok := oic.mutation.ID(); !ok { + v := orginvitation.DefaultID() + oic.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (oic *OrgInvitationCreate) check() error { + if _, ok := oic.mutation.ReceiverEmail(); !ok { + return &ValidationError{Name: "receiver_email", err: errors.New(`ent: missing required field "OrgInvitation.receiver_email"`)} + } + if _, ok := oic.mutation.Status(); !ok { + return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "OrgInvitation.status"`)} + } + if v, ok := oic.mutation.Status(); ok { + if err := orginvitation.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "OrgInvitation.status": %w`, err)} + } + } + if _, ok := oic.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "OrgInvitation.created_at"`)} + } + if _, ok := oic.mutation.OrganizationID(); !ok { + return &ValidationError{Name: "organization_id", err: errors.New(`ent: missing required field "OrgInvitation.organization_id"`)} + } + if _, ok := oic.mutation.SenderID(); !ok { + return &ValidationError{Name: "sender_id", err: errors.New(`ent: missing required field "OrgInvitation.sender_id"`)} + } + if _, ok := oic.mutation.OrganizationID(); !ok { + return &ValidationError{Name: "organization", err: errors.New(`ent: missing required edge "OrgInvitation.organization"`)} + } + if _, ok := oic.mutation.SenderID(); !ok { + return &ValidationError{Name: "sender", err: errors.New(`ent: missing required edge "OrgInvitation.sender"`)} + } + return nil +} + +func (oic *OrgInvitationCreate) sqlSave(ctx context.Context) (*OrgInvitation, error) { + if err := oic.check(); err != nil { + return nil, err + } + _node, _spec := oic.createSpec() + if err := sqlgraph.CreateNode(ctx, oic.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(*uuid.UUID); ok { + _node.ID = *id + } else if err := _node.ID.Scan(_spec.ID.Value); err != nil { + return nil, err + } + } + oic.mutation.id = &_node.ID + oic.mutation.done = true + return _node, nil +} + +func (oic *OrgInvitationCreate) createSpec() (*OrgInvitation, *sqlgraph.CreateSpec) { + var ( + _node = &OrgInvitation{config: oic.config} + _spec = sqlgraph.NewCreateSpec(orginvitation.Table, sqlgraph.NewFieldSpec(orginvitation.FieldID, field.TypeUUID)) + ) + if id, ok := oic.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = &id + } + if value, ok := oic.mutation.ReceiverEmail(); ok { + _spec.SetField(orginvitation.FieldReceiverEmail, field.TypeString, value) + _node.ReceiverEmail = value + } + if value, ok := oic.mutation.Status(); ok { + _spec.SetField(orginvitation.FieldStatus, field.TypeEnum, value) + _node.Status = value + } + if value, ok := oic.mutation.CreatedAt(); ok { + _spec.SetField(orginvitation.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := oic.mutation.DeletedAt(); ok { + _spec.SetField(orginvitation.FieldDeletedAt, field.TypeTime, value) + _node.DeletedAt = value + } + if nodes := oic.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.OrganizationTable, + Columns: []string{orginvitation.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.OrganizationID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := oic.mutation.SenderIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.SenderTable, + Columns: []string{orginvitation.SenderColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.SenderID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OrgInvitationCreateBulk is the builder for creating many OrgInvitation entities in bulk. +type OrgInvitationCreateBulk struct { + config + builders []*OrgInvitationCreate +} + +// Save creates the OrgInvitation entities in the database. +func (oicb *OrgInvitationCreateBulk) Save(ctx context.Context) ([]*OrgInvitation, error) { + specs := make([]*sqlgraph.CreateSpec, len(oicb.builders)) + nodes := make([]*OrgInvitation, len(oicb.builders)) + mutators := make([]Mutator, len(oicb.builders)) + for i := range oicb.builders { + func(i int, root context.Context) { + builder := oicb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*OrgInvitationMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, oicb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, oicb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, oicb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (oicb *OrgInvitationCreateBulk) SaveX(ctx context.Context) []*OrgInvitation { + v, err := oicb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (oicb *OrgInvitationCreateBulk) Exec(ctx context.Context) error { + _, err := oicb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (oicb *OrgInvitationCreateBulk) ExecX(ctx context.Context) { + if err := oicb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/app/controlplane/internal/data/ent/orginvitation_delete.go b/app/controlplane/internal/data/ent/orginvitation_delete.go new file mode 100644 index 000000000..6fba054db --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/predicate" +) + +// OrgInvitationDelete is the builder for deleting a OrgInvitation entity. +type OrgInvitationDelete struct { + config + hooks []Hook + mutation *OrgInvitationMutation +} + +// Where appends a list predicates to the OrgInvitationDelete builder. +func (oid *OrgInvitationDelete) Where(ps ...predicate.OrgInvitation) *OrgInvitationDelete { + oid.mutation.Where(ps...) + return oid +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (oid *OrgInvitationDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, oid.sqlExec, oid.mutation, oid.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (oid *OrgInvitationDelete) ExecX(ctx context.Context) int { + n, err := oid.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (oid *OrgInvitationDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(orginvitation.Table, sqlgraph.NewFieldSpec(orginvitation.FieldID, field.TypeUUID)) + if ps := oid.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, oid.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + oid.mutation.done = true + return affected, err +} + +// OrgInvitationDeleteOne is the builder for deleting a single OrgInvitation entity. +type OrgInvitationDeleteOne struct { + oid *OrgInvitationDelete +} + +// Where appends a list predicates to the OrgInvitationDelete builder. +func (oido *OrgInvitationDeleteOne) Where(ps ...predicate.OrgInvitation) *OrgInvitationDeleteOne { + oido.oid.mutation.Where(ps...) + return oido +} + +// Exec executes the deletion query. +func (oido *OrgInvitationDeleteOne) Exec(ctx context.Context) error { + n, err := oido.oid.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{orginvitation.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (oido *OrgInvitationDeleteOne) ExecX(ctx context.Context) { + if err := oido.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/app/controlplane/internal/data/ent/orginvitation_query.go b/app/controlplane/internal/data/ent/orginvitation_query.go new file mode 100644 index 000000000..057a686a3 --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation_query.go @@ -0,0 +1,681 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/predicate" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" + "github.com/google/uuid" +) + +// OrgInvitationQuery is the builder for querying OrgInvitation entities. +type OrgInvitationQuery struct { + config + ctx *QueryContext + order []orginvitation.OrderOption + inters []Interceptor + predicates []predicate.OrgInvitation + withOrganization *OrganizationQuery + withSender *UserQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the OrgInvitationQuery builder. +func (oiq *OrgInvitationQuery) Where(ps ...predicate.OrgInvitation) *OrgInvitationQuery { + oiq.predicates = append(oiq.predicates, ps...) + return oiq +} + +// Limit the number of records to be returned by this query. +func (oiq *OrgInvitationQuery) Limit(limit int) *OrgInvitationQuery { + oiq.ctx.Limit = &limit + return oiq +} + +// Offset to start from. +func (oiq *OrgInvitationQuery) Offset(offset int) *OrgInvitationQuery { + oiq.ctx.Offset = &offset + return oiq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (oiq *OrgInvitationQuery) Unique(unique bool) *OrgInvitationQuery { + oiq.ctx.Unique = &unique + return oiq +} + +// Order specifies how the records should be ordered. +func (oiq *OrgInvitationQuery) Order(o ...orginvitation.OrderOption) *OrgInvitationQuery { + oiq.order = append(oiq.order, o...) + return oiq +} + +// QueryOrganization chains the current query on the "organization" edge. +func (oiq *OrgInvitationQuery) QueryOrganization() *OrganizationQuery { + query := (&OrganizationClient{config: oiq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := oiq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := oiq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(orginvitation.Table, orginvitation.FieldID, selector), + sqlgraph.To(organization.Table, organization.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, orginvitation.OrganizationTable, orginvitation.OrganizationColumn), + ) + fromU = sqlgraph.SetNeighbors(oiq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QuerySender chains the current query on the "sender" edge. +func (oiq *OrgInvitationQuery) QuerySender() *UserQuery { + query := (&UserClient{config: oiq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := oiq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := oiq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(orginvitation.Table, orginvitation.FieldID, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, orginvitation.SenderTable, orginvitation.SenderColumn), + ) + fromU = sqlgraph.SetNeighbors(oiq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first OrgInvitation entity from the query. +// Returns a *NotFoundError when no OrgInvitation was found. +func (oiq *OrgInvitationQuery) First(ctx context.Context) (*OrgInvitation, error) { + nodes, err := oiq.Limit(1).All(setContextOp(ctx, oiq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{orginvitation.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (oiq *OrgInvitationQuery) FirstX(ctx context.Context) *OrgInvitation { + node, err := oiq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first OrgInvitation ID from the query. +// Returns a *NotFoundError when no OrgInvitation ID was found. +func (oiq *OrgInvitationQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = oiq.Limit(1).IDs(setContextOp(ctx, oiq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{orginvitation.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (oiq *OrgInvitationQuery) FirstIDX(ctx context.Context) uuid.UUID { + id, err := oiq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single OrgInvitation entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one OrgInvitation entity is found. +// Returns a *NotFoundError when no OrgInvitation entities are found. +func (oiq *OrgInvitationQuery) Only(ctx context.Context) (*OrgInvitation, error) { + nodes, err := oiq.Limit(2).All(setContextOp(ctx, oiq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{orginvitation.Label} + default: + return nil, &NotSingularError{orginvitation.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (oiq *OrgInvitationQuery) OnlyX(ctx context.Context) *OrgInvitation { + node, err := oiq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only OrgInvitation ID in the query. +// Returns a *NotSingularError when more than one OrgInvitation ID is found. +// Returns a *NotFoundError when no entities are found. +func (oiq *OrgInvitationQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = oiq.Limit(2).IDs(setContextOp(ctx, oiq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{orginvitation.Label} + default: + err = &NotSingularError{orginvitation.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (oiq *OrgInvitationQuery) OnlyIDX(ctx context.Context) uuid.UUID { + id, err := oiq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of OrgInvitations. +func (oiq *OrgInvitationQuery) All(ctx context.Context) ([]*OrgInvitation, error) { + ctx = setContextOp(ctx, oiq.ctx, "All") + if err := oiq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*OrgInvitation, *OrgInvitationQuery]() + return withInterceptors[[]*OrgInvitation](ctx, oiq, qr, oiq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (oiq *OrgInvitationQuery) AllX(ctx context.Context) []*OrgInvitation { + nodes, err := oiq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of OrgInvitation IDs. +func (oiq *OrgInvitationQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) { + if oiq.ctx.Unique == nil && oiq.path != nil { + oiq.Unique(true) + } + ctx = setContextOp(ctx, oiq.ctx, "IDs") + if err = oiq.Select(orginvitation.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (oiq *OrgInvitationQuery) IDsX(ctx context.Context) []uuid.UUID { + ids, err := oiq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (oiq *OrgInvitationQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, oiq.ctx, "Count") + if err := oiq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, oiq, querierCount[*OrgInvitationQuery](), oiq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (oiq *OrgInvitationQuery) CountX(ctx context.Context) int { + count, err := oiq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (oiq *OrgInvitationQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, oiq.ctx, "Exist") + switch _, err := oiq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (oiq *OrgInvitationQuery) ExistX(ctx context.Context) bool { + exist, err := oiq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the OrgInvitationQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (oiq *OrgInvitationQuery) Clone() *OrgInvitationQuery { + if oiq == nil { + return nil + } + return &OrgInvitationQuery{ + config: oiq.config, + ctx: oiq.ctx.Clone(), + order: append([]orginvitation.OrderOption{}, oiq.order...), + inters: append([]Interceptor{}, oiq.inters...), + predicates: append([]predicate.OrgInvitation{}, oiq.predicates...), + withOrganization: oiq.withOrganization.Clone(), + withSender: oiq.withSender.Clone(), + // clone intermediate query. + sql: oiq.sql.Clone(), + path: oiq.path, + } +} + +// WithOrganization tells the query-builder to eager-load the nodes that are connected to +// the "organization" edge. The optional arguments are used to configure the query builder of the edge. +func (oiq *OrgInvitationQuery) WithOrganization(opts ...func(*OrganizationQuery)) *OrgInvitationQuery { + query := (&OrganizationClient{config: oiq.config}).Query() + for _, opt := range opts { + opt(query) + } + oiq.withOrganization = query + return oiq +} + +// WithSender tells the query-builder to eager-load the nodes that are connected to +// the "sender" edge. The optional arguments are used to configure the query builder of the edge. +func (oiq *OrgInvitationQuery) WithSender(opts ...func(*UserQuery)) *OrgInvitationQuery { + query := (&UserClient{config: oiq.config}).Query() + for _, opt := range opts { + opt(query) + } + oiq.withSender = query + return oiq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// ReceiverEmail string `json:"receiver_email,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.OrgInvitation.Query(). +// GroupBy(orginvitation.FieldReceiverEmail). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (oiq *OrgInvitationQuery) GroupBy(field string, fields ...string) *OrgInvitationGroupBy { + oiq.ctx.Fields = append([]string{field}, fields...) + grbuild := &OrgInvitationGroupBy{build: oiq} + grbuild.flds = &oiq.ctx.Fields + grbuild.label = orginvitation.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// ReceiverEmail string `json:"receiver_email,omitempty"` +// } +// +// client.OrgInvitation.Query(). +// Select(orginvitation.FieldReceiverEmail). +// Scan(ctx, &v) +func (oiq *OrgInvitationQuery) Select(fields ...string) *OrgInvitationSelect { + oiq.ctx.Fields = append(oiq.ctx.Fields, fields...) + sbuild := &OrgInvitationSelect{OrgInvitationQuery: oiq} + sbuild.label = orginvitation.Label + sbuild.flds, sbuild.scan = &oiq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a OrgInvitationSelect configured with the given aggregations. +func (oiq *OrgInvitationQuery) Aggregate(fns ...AggregateFunc) *OrgInvitationSelect { + return oiq.Select().Aggregate(fns...) +} + +func (oiq *OrgInvitationQuery) prepareQuery(ctx context.Context) error { + for _, inter := range oiq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, oiq); err != nil { + return err + } + } + } + for _, f := range oiq.ctx.Fields { + if !orginvitation.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if oiq.path != nil { + prev, err := oiq.path(ctx) + if err != nil { + return err + } + oiq.sql = prev + } + return nil +} + +func (oiq *OrgInvitationQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*OrgInvitation, error) { + var ( + nodes = []*OrgInvitation{} + _spec = oiq.querySpec() + loadedTypes = [2]bool{ + oiq.withOrganization != nil, + oiq.withSender != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*OrgInvitation).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &OrgInvitation{config: oiq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, oiq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := oiq.withOrganization; query != nil { + if err := oiq.loadOrganization(ctx, query, nodes, nil, + func(n *OrgInvitation, e *Organization) { n.Edges.Organization = e }); err != nil { + return nil, err + } + } + if query := oiq.withSender; query != nil { + if err := oiq.loadSender(ctx, query, nodes, nil, + func(n *OrgInvitation, e *User) { n.Edges.Sender = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (oiq *OrgInvitationQuery) loadOrganization(ctx context.Context, query *OrganizationQuery, nodes []*OrgInvitation, init func(*OrgInvitation), assign func(*OrgInvitation, *Organization)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*OrgInvitation) + for i := range nodes { + fk := nodes[i].OrganizationID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(organization.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "organization_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (oiq *OrgInvitationQuery) loadSender(ctx context.Context, query *UserQuery, nodes []*OrgInvitation, init func(*OrgInvitation), assign func(*OrgInvitation, *User)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*OrgInvitation) + for i := range nodes { + fk := nodes[i].SenderID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(user.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "sender_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (oiq *OrgInvitationQuery) sqlCount(ctx context.Context) (int, error) { + _spec := oiq.querySpec() + _spec.Node.Columns = oiq.ctx.Fields + if len(oiq.ctx.Fields) > 0 { + _spec.Unique = oiq.ctx.Unique != nil && *oiq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, oiq.driver, _spec) +} + +func (oiq *OrgInvitationQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(orginvitation.Table, orginvitation.Columns, sqlgraph.NewFieldSpec(orginvitation.FieldID, field.TypeUUID)) + _spec.From = oiq.sql + if unique := oiq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if oiq.path != nil { + _spec.Unique = true + } + if fields := oiq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, orginvitation.FieldID) + for i := range fields { + if fields[i] != orginvitation.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if oiq.withOrganization != nil { + _spec.Node.AddColumnOnce(orginvitation.FieldOrganizationID) + } + if oiq.withSender != nil { + _spec.Node.AddColumnOnce(orginvitation.FieldSenderID) + } + } + if ps := oiq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := oiq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := oiq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := oiq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (oiq *OrgInvitationQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(oiq.driver.Dialect()) + t1 := builder.Table(orginvitation.Table) + columns := oiq.ctx.Fields + if len(columns) == 0 { + columns = orginvitation.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if oiq.sql != nil { + selector = oiq.sql + selector.Select(selector.Columns(columns...)...) + } + if oiq.ctx.Unique != nil && *oiq.ctx.Unique { + selector.Distinct() + } + for _, p := range oiq.predicates { + p(selector) + } + for _, p := range oiq.order { + p(selector) + } + if offset := oiq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := oiq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// OrgInvitationGroupBy is the group-by builder for OrgInvitation entities. +type OrgInvitationGroupBy struct { + selector + build *OrgInvitationQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (oigb *OrgInvitationGroupBy) Aggregate(fns ...AggregateFunc) *OrgInvitationGroupBy { + oigb.fns = append(oigb.fns, fns...) + return oigb +} + +// Scan applies the selector query and scans the result into the given value. +func (oigb *OrgInvitationGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, oigb.build.ctx, "GroupBy") + if err := oigb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*OrgInvitationQuery, *OrgInvitationGroupBy](ctx, oigb.build, oigb, oigb.build.inters, v) +} + +func (oigb *OrgInvitationGroupBy) sqlScan(ctx context.Context, root *OrgInvitationQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(oigb.fns)) + for _, fn := range oigb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*oigb.flds)+len(oigb.fns)) + for _, f := range *oigb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*oigb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := oigb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// OrgInvitationSelect is the builder for selecting fields of OrgInvitation entities. +type OrgInvitationSelect struct { + *OrgInvitationQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ois *OrgInvitationSelect) Aggregate(fns ...AggregateFunc) *OrgInvitationSelect { + ois.fns = append(ois.fns, fns...) + return ois +} + +// Scan applies the selector query and scans the result into the given value. +func (ois *OrgInvitationSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ois.ctx, "Select") + if err := ois.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*OrgInvitationQuery, *OrgInvitationSelect](ctx, ois.OrgInvitationQuery, ois, ois.inters, v) +} + +func (ois *OrgInvitationSelect) sqlScan(ctx context.Context, root *OrgInvitationQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ois.fns)) + for _, fn := range ois.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ois.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ois.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/app/controlplane/internal/data/ent/orginvitation_update.go b/app/controlplane/internal/data/ent/orginvitation_update.go new file mode 100644 index 000000000..4483e3a5d --- /dev/null +++ b/app/controlplane/internal/data/ent/orginvitation_update.go @@ -0,0 +1,488 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/predicate" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" + "github.com/google/uuid" +) + +// OrgInvitationUpdate is the builder for updating OrgInvitation entities. +type OrgInvitationUpdate struct { + config + hooks []Hook + mutation *OrgInvitationMutation +} + +// Where appends a list predicates to the OrgInvitationUpdate builder. +func (oiu *OrgInvitationUpdate) Where(ps ...predicate.OrgInvitation) *OrgInvitationUpdate { + oiu.mutation.Where(ps...) + return oiu +} + +// SetStatus sets the "status" field. +func (oiu *OrgInvitationUpdate) SetStatus(bis biz.OrgInvitationStatus) *OrgInvitationUpdate { + oiu.mutation.SetStatus(bis) + return oiu +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (oiu *OrgInvitationUpdate) SetNillableStatus(bis *biz.OrgInvitationStatus) *OrgInvitationUpdate { + if bis != nil { + oiu.SetStatus(*bis) + } + return oiu +} + +// SetDeletedAt sets the "deleted_at" field. +func (oiu *OrgInvitationUpdate) SetDeletedAt(t time.Time) *OrgInvitationUpdate { + oiu.mutation.SetDeletedAt(t) + return oiu +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (oiu *OrgInvitationUpdate) SetNillableDeletedAt(t *time.Time) *OrgInvitationUpdate { + if t != nil { + oiu.SetDeletedAt(*t) + } + return oiu +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (oiu *OrgInvitationUpdate) ClearDeletedAt() *OrgInvitationUpdate { + oiu.mutation.ClearDeletedAt() + return oiu +} + +// SetOrganizationID sets the "organization_id" field. +func (oiu *OrgInvitationUpdate) SetOrganizationID(u uuid.UUID) *OrgInvitationUpdate { + oiu.mutation.SetOrganizationID(u) + return oiu +} + +// SetSenderID sets the "sender_id" field. +func (oiu *OrgInvitationUpdate) SetSenderID(u uuid.UUID) *OrgInvitationUpdate { + oiu.mutation.SetSenderID(u) + return oiu +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (oiu *OrgInvitationUpdate) SetOrganization(o *Organization) *OrgInvitationUpdate { + return oiu.SetOrganizationID(o.ID) +} + +// SetSender sets the "sender" edge to the User entity. +func (oiu *OrgInvitationUpdate) SetSender(u *User) *OrgInvitationUpdate { + return oiu.SetSenderID(u.ID) +} + +// Mutation returns the OrgInvitationMutation object of the builder. +func (oiu *OrgInvitationUpdate) Mutation() *OrgInvitationMutation { + return oiu.mutation +} + +// ClearOrganization clears the "organization" edge to the Organization entity. +func (oiu *OrgInvitationUpdate) ClearOrganization() *OrgInvitationUpdate { + oiu.mutation.ClearOrganization() + return oiu +} + +// ClearSender clears the "sender" edge to the User entity. +func (oiu *OrgInvitationUpdate) ClearSender() *OrgInvitationUpdate { + oiu.mutation.ClearSender() + return oiu +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (oiu *OrgInvitationUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, oiu.sqlSave, oiu.mutation, oiu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (oiu *OrgInvitationUpdate) SaveX(ctx context.Context) int { + affected, err := oiu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (oiu *OrgInvitationUpdate) Exec(ctx context.Context) error { + _, err := oiu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (oiu *OrgInvitationUpdate) ExecX(ctx context.Context) { + if err := oiu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (oiu *OrgInvitationUpdate) check() error { + if v, ok := oiu.mutation.Status(); ok { + if err := orginvitation.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "OrgInvitation.status": %w`, err)} + } + } + if _, ok := oiu.mutation.OrganizationID(); oiu.mutation.OrganizationCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "OrgInvitation.organization"`) + } + if _, ok := oiu.mutation.SenderID(); oiu.mutation.SenderCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "OrgInvitation.sender"`) + } + return nil +} + +func (oiu *OrgInvitationUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := oiu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(orginvitation.Table, orginvitation.Columns, sqlgraph.NewFieldSpec(orginvitation.FieldID, field.TypeUUID)) + if ps := oiu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := oiu.mutation.Status(); ok { + _spec.SetField(orginvitation.FieldStatus, field.TypeEnum, value) + } + if value, ok := oiu.mutation.DeletedAt(); ok { + _spec.SetField(orginvitation.FieldDeletedAt, field.TypeTime, value) + } + if oiu.mutation.DeletedAtCleared() { + _spec.ClearField(orginvitation.FieldDeletedAt, field.TypeTime) + } + if oiu.mutation.OrganizationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.OrganizationTable, + Columns: []string{orginvitation.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := oiu.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.OrganizationTable, + Columns: []string{orginvitation.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if oiu.mutation.SenderCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.SenderTable, + Columns: []string{orginvitation.SenderColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := oiu.mutation.SenderIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.SenderTable, + Columns: []string{orginvitation.SenderColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, oiu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{orginvitation.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + oiu.mutation.done = true + return n, nil +} + +// OrgInvitationUpdateOne is the builder for updating a single OrgInvitation entity. +type OrgInvitationUpdateOne struct { + config + fields []string + hooks []Hook + mutation *OrgInvitationMutation +} + +// SetStatus sets the "status" field. +func (oiuo *OrgInvitationUpdateOne) SetStatus(bis biz.OrgInvitationStatus) *OrgInvitationUpdateOne { + oiuo.mutation.SetStatus(bis) + return oiuo +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (oiuo *OrgInvitationUpdateOne) SetNillableStatus(bis *biz.OrgInvitationStatus) *OrgInvitationUpdateOne { + if bis != nil { + oiuo.SetStatus(*bis) + } + return oiuo +} + +// SetDeletedAt sets the "deleted_at" field. +func (oiuo *OrgInvitationUpdateOne) SetDeletedAt(t time.Time) *OrgInvitationUpdateOne { + oiuo.mutation.SetDeletedAt(t) + return oiuo +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (oiuo *OrgInvitationUpdateOne) SetNillableDeletedAt(t *time.Time) *OrgInvitationUpdateOne { + if t != nil { + oiuo.SetDeletedAt(*t) + } + return oiuo +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (oiuo *OrgInvitationUpdateOne) ClearDeletedAt() *OrgInvitationUpdateOne { + oiuo.mutation.ClearDeletedAt() + return oiuo +} + +// SetOrganizationID sets the "organization_id" field. +func (oiuo *OrgInvitationUpdateOne) SetOrganizationID(u uuid.UUID) *OrgInvitationUpdateOne { + oiuo.mutation.SetOrganizationID(u) + return oiuo +} + +// SetSenderID sets the "sender_id" field. +func (oiuo *OrgInvitationUpdateOne) SetSenderID(u uuid.UUID) *OrgInvitationUpdateOne { + oiuo.mutation.SetSenderID(u) + return oiuo +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (oiuo *OrgInvitationUpdateOne) SetOrganization(o *Organization) *OrgInvitationUpdateOne { + return oiuo.SetOrganizationID(o.ID) +} + +// SetSender sets the "sender" edge to the User entity. +func (oiuo *OrgInvitationUpdateOne) SetSender(u *User) *OrgInvitationUpdateOne { + return oiuo.SetSenderID(u.ID) +} + +// Mutation returns the OrgInvitationMutation object of the builder. +func (oiuo *OrgInvitationUpdateOne) Mutation() *OrgInvitationMutation { + return oiuo.mutation +} + +// ClearOrganization clears the "organization" edge to the Organization entity. +func (oiuo *OrgInvitationUpdateOne) ClearOrganization() *OrgInvitationUpdateOne { + oiuo.mutation.ClearOrganization() + return oiuo +} + +// ClearSender clears the "sender" edge to the User entity. +func (oiuo *OrgInvitationUpdateOne) ClearSender() *OrgInvitationUpdateOne { + oiuo.mutation.ClearSender() + return oiuo +} + +// Where appends a list predicates to the OrgInvitationUpdate builder. +func (oiuo *OrgInvitationUpdateOne) Where(ps ...predicate.OrgInvitation) *OrgInvitationUpdateOne { + oiuo.mutation.Where(ps...) + return oiuo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (oiuo *OrgInvitationUpdateOne) Select(field string, fields ...string) *OrgInvitationUpdateOne { + oiuo.fields = append([]string{field}, fields...) + return oiuo +} + +// Save executes the query and returns the updated OrgInvitation entity. +func (oiuo *OrgInvitationUpdateOne) Save(ctx context.Context) (*OrgInvitation, error) { + return withHooks(ctx, oiuo.sqlSave, oiuo.mutation, oiuo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (oiuo *OrgInvitationUpdateOne) SaveX(ctx context.Context) *OrgInvitation { + node, err := oiuo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (oiuo *OrgInvitationUpdateOne) Exec(ctx context.Context) error { + _, err := oiuo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (oiuo *OrgInvitationUpdateOne) ExecX(ctx context.Context) { + if err := oiuo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (oiuo *OrgInvitationUpdateOne) check() error { + if v, ok := oiuo.mutation.Status(); ok { + if err := orginvitation.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "OrgInvitation.status": %w`, err)} + } + } + if _, ok := oiuo.mutation.OrganizationID(); oiuo.mutation.OrganizationCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "OrgInvitation.organization"`) + } + if _, ok := oiuo.mutation.SenderID(); oiuo.mutation.SenderCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "OrgInvitation.sender"`) + } + return nil +} + +func (oiuo *OrgInvitationUpdateOne) sqlSave(ctx context.Context) (_node *OrgInvitation, err error) { + if err := oiuo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(orginvitation.Table, orginvitation.Columns, sqlgraph.NewFieldSpec(orginvitation.FieldID, field.TypeUUID)) + id, ok := oiuo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "OrgInvitation.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := oiuo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, orginvitation.FieldID) + for _, f := range fields { + if !orginvitation.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != orginvitation.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := oiuo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := oiuo.mutation.Status(); ok { + _spec.SetField(orginvitation.FieldStatus, field.TypeEnum, value) + } + if value, ok := oiuo.mutation.DeletedAt(); ok { + _spec.SetField(orginvitation.FieldDeletedAt, field.TypeTime, value) + } + if oiuo.mutation.DeletedAtCleared() { + _spec.ClearField(orginvitation.FieldDeletedAt, field.TypeTime) + } + if oiuo.mutation.OrganizationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.OrganizationTable, + Columns: []string{orginvitation.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := oiuo.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.OrganizationTable, + Columns: []string{orginvitation.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if oiuo.mutation.SenderCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.SenderTable, + Columns: []string{orginvitation.SenderColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := oiuo.mutation.SenderIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: orginvitation.SenderTable, + Columns: []string{orginvitation.SenderColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &OrgInvitation{config: oiuo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, oiuo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{orginvitation.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + oiuo.mutation.done = true + return _node, nil +} diff --git a/app/controlplane/internal/data/ent/predicate/predicate.go b/app/controlplane/internal/data/ent/predicate/predicate.go index 835879f22..a563b3b32 100644 --- a/app/controlplane/internal/data/ent/predicate/predicate.go +++ b/app/controlplane/internal/data/ent/predicate/predicate.go @@ -21,6 +21,9 @@ type IntegrationAttachment func(*sql.Selector) // Membership is the predicate function for membership builders. type Membership func(*sql.Selector) +// OrgInvitation is the predicate function for orginvitation builders. +type OrgInvitation func(*sql.Selector) + // Organization is the predicate function for organization builders. type Organization func(*sql.Selector) diff --git a/app/controlplane/internal/data/ent/runtime.go b/app/controlplane/internal/data/ent/runtime.go index 7ce97e8fa..9b43534b6 100644 --- a/app/controlplane/internal/data/ent/runtime.go +++ b/app/controlplane/internal/data/ent/runtime.go @@ -11,6 +11,7 @@ import ( "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/integrationattachment" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/membership" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/robotaccount" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/schema" "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/user" @@ -95,6 +96,16 @@ func init() { membershipDescID := membershipFields[0].Descriptor() // membership.DefaultID holds the default value on creation for the id field. membership.DefaultID = membershipDescID.Default.(func() uuid.UUID) + orginvitationFields := schema.OrgInvitation{}.Fields() + _ = orginvitationFields + // orginvitationDescCreatedAt is the schema descriptor for created_at field. + orginvitationDescCreatedAt := orginvitationFields[3].Descriptor() + // orginvitation.DefaultCreatedAt holds the default value on creation for the created_at field. + orginvitation.DefaultCreatedAt = orginvitationDescCreatedAt.Default.(func() time.Time) + // orginvitationDescID is the schema descriptor for id field. + orginvitationDescID := orginvitationFields[0].Descriptor() + // orginvitation.DefaultID holds the default value on creation for the id field. + orginvitation.DefaultID = orginvitationDescID.Default.(func() uuid.UUID) organizationFields := schema.Organization{}.Fields() _ = organizationFields // organizationDescName is the schema descriptor for name field. diff --git a/app/controlplane/internal/data/ent/schema-viz.html b/app/controlplane/internal/data/ent/schema-viz.html index 341306ae8..67d03616a 100644 --- a/app/controlplane/internal/data/ent/schema-viz.html +++ b/app/controlplane/internal/data/ent/schema-viz.html @@ -70,7 +70,7 @@ } - const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"}]}],\"edges\":[{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"WorkflowRun\",\"label\":\"workflow_run\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"RobotAccount\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"}]}"); + const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"}]}],\"edges\":[{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"WorkflowRun\",\"label\":\"workflow_run\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"RobotAccount\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"}]}"); const nodes = new vis.DataSet((entGraph.nodes || []).map(n => ({ id: n.id, diff --git a/app/controlplane/internal/data/ent/schema/orginvitation.go b/app/controlplane/internal/data/ent/schema/orginvitation.go new file mode 100644 index 000000000..7535cf630 --- /dev/null +++ b/app/controlplane/internal/data/ent/schema/orginvitation.go @@ -0,0 +1,57 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/google/uuid" +) + +type OrgInvitation struct { + ent.Schema +} + +func (OrgInvitation) Fields() []ent.Field { + return []ent.Field{ + field.UUID("id", uuid.UUID{}).Default(uuid.New).Unique(), + field.String("receiver_email").Immutable(), + field.Enum("status"). + GoType(biz.OrgInvitationStatus("")). + Default(string(biz.OrgInvitationStatusPending)), + field.Time("created_at"). + Default(time.Now). + Immutable(). + Annotations(&entsql.Annotation{Default: "CURRENT_TIMESTAMP"}), + field.Time("deleted_at").Optional(), + + // edge fields to be able to access to them directly + field.UUID("organization_id", uuid.UUID{}), + field.UUID("sender_id", uuid.UUID{}), + } +} + +func (OrgInvitation) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("organization", Organization.Type).Unique().Required().Field("organization_id"), + edge.To("sender", User.Type).Unique().Required().Field("sender_id"), + } +} diff --git a/app/controlplane/internal/data/ent/tx.go b/app/controlplane/internal/data/ent/tx.go index 7b08012b8..6c0845813 100644 --- a/app/controlplane/internal/data/ent/tx.go +++ b/app/controlplane/internal/data/ent/tx.go @@ -22,6 +22,8 @@ type Tx struct { IntegrationAttachment *IntegrationAttachmentClient // Membership is the client for interacting with the Membership builders. Membership *MembershipClient + // OrgInvitation is the client for interacting with the OrgInvitation builders. + OrgInvitation *OrgInvitationClient // Organization is the client for interacting with the Organization builders. Organization *OrganizationClient // RobotAccount is the client for interacting with the RobotAccount builders. @@ -172,6 +174,7 @@ func (tx *Tx) init() { tx.Integration = NewIntegrationClient(tx.config) tx.IntegrationAttachment = NewIntegrationAttachmentClient(tx.config) tx.Membership = NewMembershipClient(tx.config) + tx.OrgInvitation = NewOrgInvitationClient(tx.config) tx.Organization = NewOrganizationClient(tx.config) tx.RobotAccount = NewRobotAccountClient(tx.config) tx.User = NewUserClient(tx.config) diff --git a/app/controlplane/internal/data/membership.go b/app/controlplane/internal/data/membership.go index bf6d39fea..02a5ac243 100644 --- a/app/controlplane/internal/data/membership.go +++ b/app/controlplane/internal/data/membership.go @@ -79,7 +79,7 @@ func (r *MembershipRepo) FindByUser(ctx context.Context, userID uuid.UUID) ([]*b // FindByOrg finds all memberships for a given organization func (r *MembershipRepo) FindByOrg(ctx context.Context, orgID uuid.UUID) ([]*biz.Membership, error) { memberships, err := orgScopedQuery(r.data.db, orgID). - QueryMemberships(). + QueryMemberships().WithUser(). WithOrganization().All(ctx) if err != nil { return nil, err @@ -162,6 +162,7 @@ func entMembershipToBiz(m *ent.Membership) *biz.Membership { if m.Edges.User != nil { res.UserID = m.Edges.User.ID + res.UserEmail = m.Edges.User.Email } return res diff --git a/app/controlplane/internal/data/orginvitation.go b/app/controlplane/internal/data/orginvitation.go new file mode 100644 index 000000000..7fa541424 --- /dev/null +++ b/app/controlplane/internal/data/orginvitation.go @@ -0,0 +1,148 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package data + +import ( + "context" + "fmt" + "time" + + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/data/ent/orginvitation" + "github.com/go-kratos/kratos/v2/log" + "github.com/google/uuid" +) + +type OrgInvitation struct { + data *Data + log *log.Helper +} + +func NewOrgInvitation(data *Data, logger log.Logger) biz.OrgInvitationRepo { + return &OrgInvitation{ + data: data, + log: log.NewHelper(logger), + } +} + +func (r *OrgInvitation) Create(ctx context.Context, orgID, senderID uuid.UUID, receiverEmail string) (*biz.OrgInvitation, error) { + invite, err := r.data.db.OrgInvitation.Create(). + SetOrganizationID(orgID). + SetSenderID(senderID). + SetReceiverEmail(receiverEmail). + Save(ctx) + + if err != nil { + return nil, err + } + + return r.FindByID(ctx, invite.ID) +} + +func (r *OrgInvitation) PendingInvitation(ctx context.Context, orgID uuid.UUID, receiverEmail string) (*biz.OrgInvitation, error) { + invite, err := r.query(). + Where( + orginvitation.OrganizationID(orgID), + orginvitation.ReceiverEmail(receiverEmail), + orginvitation.StatusEQ(biz.OrgInvitationStatusPending), + ).Only(ctx) + if err != nil && !ent.IsNotFound(err) { + return nil, err + } else if invite == nil { + return nil, nil + } + + return entInviteToBiz(invite), nil +} + +func (r *OrgInvitation) PendingInvitations(ctx context.Context, receiverEmail string) ([]*biz.OrgInvitation, error) { + invites, err := r.query().Where( + orginvitation.ReceiverEmail(receiverEmail), + orginvitation.StatusEQ(biz.OrgInvitationStatusPending), + ).All(ctx) + if err != nil { + return nil, fmt.Errorf("error finding invites for user %s: %w", receiverEmail, err) + } + + res := make([]*biz.OrgInvitation, len(invites)) + for i, v := range invites { + res[i] = entInviteToBiz(v) + } + + return res, nil +} + +func (r *OrgInvitation) ChangeStatus(ctx context.Context, id uuid.UUID, status biz.OrgInvitationStatus) error { + return r.data.db.OrgInvitation.UpdateOneID(id).SetStatus(status).Exec(ctx) +} + +// Full query of non-deleted invites with all edges loaded +func (r *OrgInvitation) query() *ent.OrgInvitationQuery { + return r.data.db.OrgInvitation.Query().WithOrganization().WithSender().Where(orginvitation.DeletedAtIsNil()) +} + +func (r *OrgInvitation) FindByID(ctx context.Context, id uuid.UUID) (*biz.OrgInvitation, error) { + invite, err := r.query().Where(orginvitation.ID(id)).Only(ctx) + if err != nil && !ent.IsNotFound(err) { + return nil, fmt.Errorf("error finding invite %s: %w", id.String(), err) + } else if invite == nil { + return nil, nil + } + + return entInviteToBiz(invite), nil +} + +func (r *OrgInvitation) SoftDelete(ctx context.Context, id uuid.UUID) error { + return r.data.db.OrgInvitation.UpdateOneID(id).SetDeletedAt(time.Now()).Exec(ctx) +} + +func (r *OrgInvitation) ListBySender(ctx context.Context, userID uuid.UUID) ([]*biz.OrgInvitation, error) { + invite, err := r.query().Where(orginvitation.SenderID(userID)).All(ctx) + if err != nil { + return nil, fmt.Errorf("error finding invites for user %s: %w", userID.String(), err) + } + + res := make([]*biz.OrgInvitation, len(invite)) + for i, v := range invite { + res[i] = entInviteToBiz(v) + } + + return res, nil +} + +func entInviteToBiz(i *ent.OrgInvitation) *biz.OrgInvitation { + if i == nil { + return nil + } + + res := &biz.OrgInvitation{ + ID: i.ID, + ReceiverEmail: i.ReceiverEmail, + CreatedAt: toTimePtr(i.CreatedAt), + Status: i.Status, + } + + if i.Edges.Organization != nil { + res.Org = entOrgToBizOrg(i.Edges.Organization) + } + + if i.Edges.Sender != nil { + res.Sender = entUserToBizUser(i.Edges.Sender) + } + + return res +} diff --git a/app/controlplane/internal/data/user.go b/app/controlplane/internal/data/user.go index 8fb8ed8dc..df924d863 100644 --- a/app/controlplane/internal/data/user.go +++ b/app/controlplane/internal/data/user.go @@ -56,7 +56,8 @@ func (r *userRepo) CreateByEmail(ctx context.Context, email string) (*biz.User, return nil, err } - return entUserToBizUser(u), nil + // Query it to load the fully formed object, including proper casted dates that come from the DB + return r.FindByID(ctx, u.ID) } // Find by ID, returns nil if not found diff --git a/app/controlplane/internal/server/grpc.go b/app/controlplane/internal/server/grpc.go index 51dd9bcda..58aa2a0c7 100644 --- a/app/controlplane/internal/server/grpc.go +++ b/app/controlplane/internal/server/grpc.go @@ -65,6 +65,7 @@ type Opts struct { OrganizationSvc *service.OrganizationService CASBackendSvc *service.CASBackendService CASRedirectSvc *service.CASRedirectService + OrgInvitationSvc *service.OrgInvitationService // Utils Logger log.Logger ServerConfig *conf.Server @@ -121,6 +122,7 @@ func NewGRPCServer(opts *Opts) (*grpc.Server, error) { v1.RegisterAuthServiceServer(srv, opts.AuthSvc) v1.RegisterCASBackendServiceServer(srv, opts.CASBackendSvc) v1.RegisterCASRedirectServiceServer(srv, opts.CASRedirectSvc) + v1.RegisterOrgInvitationServiceServer(srv, opts.OrgInvitationSvc) // Register Prometheus metrics grpc_prometheus.Register(srv.Server) diff --git a/app/controlplane/internal/service/auth.go b/app/controlplane/internal/service/auth.go index 3b931828c..b4c7f88a9 100644 --- a/app/controlplane/internal/service/auth.go +++ b/app/controlplane/internal/service/auth.go @@ -70,10 +70,11 @@ type AuthService struct { orgUseCase *biz.OrganizationUseCase casBackendUseCase *biz.CASBackendUseCase membershipUseCase *biz.MembershipUseCase + orgInvitesUseCase *biz.OrgInvitationUseCase AuthURLs *AuthURLs } -func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, cbUC *biz.CASBackendUseCase, authConfig *conf.Auth, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { +func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC *biz.MembershipUseCase, cbUC *biz.CASBackendUseCase, inviteUC *biz.OrgInvitationUseCase, authConfig *conf.Auth, serverConfig *conf.Server, opts ...NewOpt) (*AuthService, error) { oidcConfig := authConfig.GetOidc() if oidcConfig == nil { return nil, errors.New("oauth configuration missing") @@ -99,6 +100,7 @@ func NewAuthService(userUC *biz.UserUseCase, orgUC *biz.OrganizationUseCase, mUC AuthURLs: authURLs, membershipUseCase: mUC, casBackendUseCase: cbUC, + orgInvitesUseCase: inviteUC, }, nil } @@ -225,6 +227,11 @@ func callbackHandler(svc *AuthService, w http.ResponseWriter, r *http.Request) ( svc.log.Infow("msg", "new user associated to an org", "org_id", currentOrg.ID, "user_id", u.ID) } + // Accept any pending invites + if err := svc.orgInvitesUseCase.AcceptPendingInvitations(ctx, u.Email); err != nil { + return http.StatusInternalServerError, sl.LogAndMaskErr(err, svc.log) + } + // Create a default inline CAS backend if none exists backend, err := svc.casBackendUseCase.FindFallbackBackend(ctx, currentOrg.ID) if err != nil && !biz.IsNotFound(err) { diff --git a/app/controlplane/internal/service/context.go b/app/controlplane/internal/service/context.go index adb847a49..a4afe3c18 100644 --- a/app/controlplane/internal/service/context.go +++ b/app/controlplane/internal/service/context.go @@ -68,3 +68,7 @@ func (s *ContextService) Current(ctx context.Context, _ *pb.ContextServiceCurren func bizOrgToPb(m *biz.Organization) *pb.Org { return &pb.Org{Id: m.ID, Name: m.Name, CreatedAt: timestamppb.New(*m.CreatedAt)} } + +func bizUserToPb(u *biz.User) *pb.User { + return &pb.User{Id: u.ID, Email: u.Email, CreatedAt: timestamppb.New(*u.CreatedAt)} +} diff --git a/app/controlplane/internal/service/orginvitation.go b/app/controlplane/internal/service/orginvitation.go new file mode 100644 index 000000000..6ec6733a1 --- /dev/null +++ b/app/controlplane/internal/service/orginvitation.go @@ -0,0 +1,93 @@ +// +// Copyright 2023 The Chainloop Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package service + +import ( + "context" + + pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" + "github.com/chainloop-dev/chainloop/app/controlplane/internal/biz" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type OrgInvitationService struct { + pb.UnimplementedOrgInvitationServiceServer + *service + + useCase *biz.OrgInvitationUseCase +} + +func NewOrgInvitationService(uc *biz.OrgInvitationUseCase, opts ...NewOpt) *OrgInvitationService { + return &OrgInvitationService{ + service: newService(opts...), + useCase: uc, + } +} + +func (s *OrgInvitationService) Create(ctx context.Context, req *pb.OrgInvitationServiceCreateRequest) (*pb.OrgInvitationServiceCreateResponse, error) { + user, _, err := loadCurrentUserAndOrg(ctx) + if err != nil { + return nil, err + } + + // Validations and rbac checks are done in the biz layer + i, err := s.useCase.Create(ctx, req.OrganizationId, user.ID, req.ReceiverEmail) + if err != nil { + return nil, handleUseCaseErr("invitation", err, s.log) + } + + return &pb.OrgInvitationServiceCreateResponse{Result: bizInvitationToPB(i)}, nil +} + +func (s *OrgInvitationService) Revoke(ctx context.Context, req *pb.OrgInvitationServiceRevokeRequest) (*pb.OrgInvitationServiceRevokeResponse, error) { + user, _, err := loadCurrentUserAndOrg(ctx) + if err != nil { + return nil, err + } + + if err := s.useCase.Revoke(ctx, user.ID, req.Id); err != nil { + return nil, handleUseCaseErr("invitation", err, s.log) + } + + return &pb.OrgInvitationServiceRevokeResponse{}, nil +} + +func (s *OrgInvitationService) ListSent(ctx context.Context, _ *pb.OrgInvitationServiceListSentRequest) (*pb.OrgInvitationServiceListSentResponse, error) { + user, _, err := loadCurrentUserAndOrg(ctx) + if err != nil { + return nil, err + } + + invitations, err := s.useCase.ListBySender(ctx, user.ID) + if err != nil { + return nil, handleUseCaseErr("invitation", err, s.log) + } + + res := []*pb.OrgInvitationItem{} + for _, invitation := range invitations { + res = append(res, bizInvitationToPB(invitation)) + } + + return &pb.OrgInvitationServiceListSentResponse{Result: res}, nil +} + +func bizInvitationToPB(e *biz.OrgInvitation) *pb.OrgInvitationItem { + return &pb.OrgInvitationItem{ + Id: e.ID.String(), CreatedAt: timestamppb.New(*e.CreatedAt), + ReceiverEmail: e.ReceiverEmail, Status: string(e.Status), + Organization: bizOrgToPb(e.Org), Sender: bizUserToPb(e.Sender), + } +} diff --git a/app/controlplane/internal/service/service.go b/app/controlplane/internal/service/service.go index 87ca39a81..4903ee7af 100644 --- a/app/controlplane/internal/service/service.go +++ b/app/controlplane/internal/service/service.go @@ -43,6 +43,7 @@ var ProviderSet = wire.NewSet( NewCASBackendService, NewCASRedirectService, NewOrganizationService, + NewOrgInvitationService, wire.Struct(new(NewWorkflowRunServiceOpts), "*"), wire.Struct(new(NewAttestationServiceOpts), "*"), ) @@ -81,11 +82,14 @@ func WithLogger(logger log.Logger) NewOpt { } func handleUseCaseErr(entity string, err error, l *log.Helper) error { - if biz.IsErrValidation(err) { + switch { + case biz.IsErrValidation(err): return errors.BadRequest(fmt.Sprintf("invalid %s", entity), err.Error()) - } else if biz.IsNotFound(err) { + case biz.IsNotFound(err): return errors.NotFound(fmt.Sprintf("%s not found", entity), err.Error()) + case biz.IsErrUnauthorized(err): + return errors.Forbidden(fmt.Sprintf("unauthorized %s", entity), err.Error()) + default: + return servicelogger.LogAndMaskErr(err, l) } - - return servicelogger.LogAndMaskErr(err, l) }