Files
paralus/pkg/service/partner.go
Swastik GourandGitHub 7a4895a5b2 updated main.go script to reinitialize the permissions when the are e… (#366)
* updated main.go script to reinitialize the permissions when the are existing or there is any update

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added few corrections and added better error logging

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added the checks for checking the existence of different components

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* started adding the Upsert function

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added upsert to role.go

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added tests and auditing

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* updated packages

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* updated go version

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added minor changes

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* added correction to role_test.go

Signed-off-by: swastik959 <Sswastik959@gmail.com>

* corrected test cases

Signed-off-by: swastik959 <Sswastik959@gmail.com>

---------

Signed-off-by: swastik959 <Sswastik959@gmail.com>
2025-03-20 16:15:38 +05:30

391 lines
12 KiB
Go

package service
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/google/uuid"
"github.com/paralus/paralus/internal/dao"
"github.com/paralus/paralus/internal/models"
commonv3 "github.com/paralus/paralus/proto/types/commonpb/v3"
v3 "github.com/paralus/paralus/proto/types/commonpb/v3"
systemv3 "github.com/paralus/paralus/proto/types/systempb/v3"
bun "github.com/uptrace/bun"
"go.uber.org/zap"
"google.golang.org/protobuf/types/known/timestamppb"
)
// PartnerService is the interface for partner operations
type PartnerService interface {
// create partner
Create(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error)
// get partner by id
GetByID(ctx context.Context, partnerId string) (*systemv3.Partner, error)
// get partner by id
GetByName(ctx context.Context, name string) (*systemv3.Partner, error)
// create or update partner
Update(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error)
// delete partner
Delete(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error)
// list partner
GetOnlyPartner(ctx context.Context) (*systemv3.Partner, error)
// Upsert partner
Upsert(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error)
}
// partnerService implements PartnerService
type partnerService struct {
db *bun.DB
al *zap.Logger
}
// NewPartnerService return new partner service
func NewPartnerService(db *bun.DB, al *zap.Logger) PartnerService {
return &partnerService{db, al}
}
func (s *partnerService) Create(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error) {
var sb []byte
if partner.GetSpec().GetSettings() != nil {
sb = json.RawMessage(partner.GetSpec().GetSettings().String())
}
//convert v3 spec to internal models
part := models.Partner{
Name: partner.GetMetadata().GetName(),
Description: partner.GetMetadata().GetDescription(),
Trash: false,
Settings: sb,
Host: partner.GetSpec().GetHost(),
Domain: partner.GetSpec().GetDomain(),
TosLink: partner.GetSpec().GetTosLink(),
LogoLink: partner.GetSpec().GetLogoLink(),
NotificationEmail: partner.GetSpec().GetNotificationEmail(),
HelpdeskEmail: partner.GetSpec().GetHelpdeskEmail(),
ProductName: partner.GetSpec().GetProductName(),
SupportTeamName: partner.GetSpec().GetSupportTeamName(),
OpsHost: partner.GetSpec().GetOpsHost(),
FavIconLink: partner.GetSpec().GetFavIconLink(),
IsTOTPEnabled: partner.GetSpec().GetIsTOTPEnabled(),
IsSyntheticPartnerEnabled: false,
CreatedAt: time.Now(),
ModifiedAt: time.Now(),
}
entity, err := dao.Create(ctx, s.db, &part)
if err != nil {
return &systemv3.Partner{}, err
}
if createdPartner, ok := entity.(*models.Partner); ok {
//update v3 spec
partner.Metadata.Id = createdPartner.ID.String()
partner.Metadata.ModifiedAt = timestamppb.New(createdPartner.ModifiedAt)
CreatePartnerAuditEvent(ctx, s.al, AuditActionCreate, partner.GetMetadata().GetName(), createdPartner.ID)
}
return partner, nil
}
func (s *partnerService) GetByID(ctx context.Context, id string) (*systemv3.Partner, error) {
partner := &systemv3.Partner{
ApiVersion: apiVersion,
Kind: partnerKind,
Metadata: &v3.Metadata{
Id: id,
},
}
uid, err := uuid.Parse(id)
if err != nil {
return &systemv3.Partner{}, err
}
entity, err := dao.GetByID(ctx, s.db, uid, &models.Partner{})
if err != nil {
return &systemv3.Partner{}, err
}
if part, ok := entity.(*models.Partner); ok {
partner.Metadata = &v3.Metadata{
Name: part.Name,
Description: part.Description,
ModifiedAt: timestamppb.New(part.ModifiedAt),
}
partner.Spec = &systemv3.PartnerSpec{
Host: part.Host,
Domain: part.Domain,
TosLink: part.TosLink,
LogoLink: part.LogoLink,
NotificationEmail: part.NotificationEmail,
HelpdeskEmail: part.HelpdeskEmail,
ProductName: part.ProductName,
SupportTeamName: part.SupportTeamName,
OpsHost: part.OpsHost,
FavIconLink: part.FavIconLink,
IsTOTPEnabled: part.IsTOTPEnabled,
Settings: nil, //TODO
}
return partner, nil
} else {
partner := &systemv3.Partner{
ApiVersion: apiVersion,
Kind: partnerKind,
Metadata: &v3.Metadata{
Id: id,
},
Status: &v3.Status{
ConditionStatus: v3.ConditionStatus_StatusNotSet,
Reason: "Unable to fetch partner information",
LastUpdated: timestamppb.Now(),
},
}
return partner, nil
}
}
func (s *partnerService) GetByName(ctx context.Context, name string) (*systemv3.Partner, error) {
partner := &systemv3.Partner{
ApiVersion: apiVersion,
Kind: partnerKind,
Metadata: &v3.Metadata{
Name: name,
},
}
entity, err := dao.GetByName(ctx, s.db, name, &models.Partner{})
if err != nil {
return &systemv3.Partner{}, err
}
if part, ok := entity.(*models.Partner); ok {
partner.Metadata = &v3.Metadata{
Name: part.Name,
Id: part.ID.String(),
Description: part.Description,
ModifiedAt: timestamppb.New(part.ModifiedAt),
}
partner.Spec = &systemv3.PartnerSpec{
Host: part.Host,
Domain: part.Domain,
TosLink: part.TosLink,
LogoLink: part.LogoLink,
NotificationEmail: part.NotificationEmail,
HelpdeskEmail: part.HelpdeskEmail,
ProductName: part.ProductName,
SupportTeamName: part.SupportTeamName,
OpsHost: part.OpsHost,
FavIconLink: part.FavIconLink,
IsTOTPEnabled: part.IsTOTPEnabled,
Settings: nil, //TODO
}
return partner, nil
} else {
partner := &systemv3.Partner{
ApiVersion: apiVersion,
Kind: partnerKind,
Metadata: &v3.Metadata{
Name: name,
},
Status: &v3.Status{
ConditionType: "Describe",
ConditionStatus: v3.ConditionStatus_StatusNotSet,
Reason: "Unable to fetch partner information",
LastUpdated: timestamppb.Now(),
},
}
return partner, nil
}
}
func (s *partnerService) Update(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error) {
entity, err := dao.GetByName(ctx, s.db, partner.Metadata.Name, &models.Partner{})
if err != nil {
return &systemv3.Partner{}, err
}
var sb []byte
if partner.GetSpec().GetSettings() != nil {
sb = json.RawMessage(partner.GetSpec().GetSettings().String())
}
if part, ok := entity.(*models.Partner); ok {
//update partner details
part.Name = partner.GetMetadata().Name
part.Description = partner.GetMetadata().GetDescription()
part.Settings = sb
part.Host = partner.GetSpec().GetHost()
part.Domain = partner.GetSpec().GetDomain()
part.TosLink = partner.GetSpec().GetTosLink()
part.LogoLink = partner.GetSpec().GetLogoLink()
part.NotificationEmail = partner.GetSpec().GetNotificationEmail()
part.HelpdeskEmail = partner.GetSpec().GetHelpdeskEmail()
part.ProductName = partner.GetSpec().GetProductName()
part.SupportTeamName = partner.GetSpec().GetSupportTeamName()
part.OpsHost = partner.GetSpec().GetOpsHost()
part.FavIconLink = partner.GetSpec().GetFavIconLink()
part.IsTOTPEnabled = partner.GetSpec().GetIsTOTPEnabled()
part.ModifiedAt = time.Now()
//Update the partner details
_, err = dao.Update(ctx, s.db, part.ID, part)
if err != nil {
return &systemv3.Partner{}, err
}
//update metadata and status
partner.Metadata.ModifiedAt = timestamppb.New(part.ModifiedAt)
CreatePartnerAuditEvent(ctx, s.al, AuditActionUpdate, partner.GetMetadata().GetName(), part.ID)
}
return partner, nil
}
func (s *partnerService) Delete(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error) {
entity, err := dao.GetByName(ctx, s.db, partner.Metadata.Name, &models.Partner{})
if err != nil {
return &systemv3.Partner{}, err
}
if part, ok := entity.(*models.Partner); ok {
err := dao.Delete(ctx, s.db, part.ID, part)
if err != nil {
return &systemv3.Partner{}, err
}
CreatePartnerAuditEvent(ctx, s.al, AuditActionDelete, partner.GetMetadata().GetName(), part.ID)
return partner, nil
}
return partner, nil
}
func (s *partnerService) GetOnlyPartner(ctx context.Context) (partner *systemv3.Partner, err error) {
var partners []models.Partner
entities, err := dao.ListAll(ctx, s.db, &partners)
if err != nil {
return nil, err
}
if pts, ok := entities.(*[]models.Partner); ok {
for _, part := range *pts {
partner = &systemv3.Partner{
Metadata: &v3.Metadata{
Name: part.Name,
Id: part.ID.String(),
Description: part.Description,
ModifiedAt: timestamppb.New(part.ModifiedAt),
},
Spec: &systemv3.PartnerSpec{
Host: part.Host,
Domain: part.Domain,
TosLink: part.TosLink,
LogoLink: part.LogoLink,
NotificationEmail: part.NotificationEmail,
HelpdeskEmail: part.HelpdeskEmail,
ProductName: part.ProductName,
SupportTeamName: part.SupportTeamName,
OpsHost: part.OpsHost,
FavIconLink: part.FavIconLink,
IsTOTPEnabled: part.IsTOTPEnabled,
Settings: nil,
},
Status: &v3.Status{
ConditionType: "Describe",
ConditionStatus: v3.ConditionStatus_StatusOK,
LastUpdated: timestamppb.New(part.ModifiedAt),
},
}
return partner, nil
}
}
return partner, err
}
func (s *partnerService) Upsert(ctx context.Context, partner *systemv3.Partner) (*systemv3.Partner, error) {
// Convert settings to JSON if needed
sb, err := json.Marshal(map[string]interface{}{})
if err != nil {
return nil, fmt.Errorf("failed to marshal settings: %v", err)
}
p := models.Partner{
Name: partner.GetMetadata().GetName(),
Description: partner.GetMetadata().GetDescription(),
Trash: false,
Settings: sb,
Host: partner.GetSpec().GetHost(),
Domain: partner.GetSpec().GetDomain(),
TosLink: partner.GetSpec().GetTosLink(),
LogoLink: partner.GetSpec().GetLogoLink(),
NotificationEmail: partner.GetSpec().GetNotificationEmail(),
HelpdeskEmail: partner.GetSpec().GetHelpdeskEmail(),
ProductName: partner.GetSpec().GetProductName(),
SupportTeamName: partner.GetSpec().GetSupportTeamName(),
OpsHost: partner.GetSpec().GetOpsHost(),
FavIconLink: partner.GetSpec().GetFavIconLink(),
IsTOTPEnabled: partner.GetSpec().GetIsTOTPEnabled(),
IsSyntheticPartnerEnabled: false,
CreatedAt: time.Now(),
ModifiedAt: time.Now(),
}
_, err = s.db.NewInsert().
Model(&p).
On("CONFLICT (name) WHERE trash IS FALSE DO UPDATE").
Set("description = EXCLUDED.description").
Set("host = EXCLUDED.host").
Set("domain = EXCLUDED.domain").
Set("tos_link = EXCLUDED.tos_link").
Set("logo_link = EXCLUDED.logo_link").
Set("notification_email = EXCLUDED.notification_email").
Set("support_team_name = EXCLUDED.support_team_name").
Set("ops_host = EXCLUDED.ops_host").
Set("fav_icon_link = EXCLUDED.fav_icon_link").
Set("is_totp_enabled = EXCLUDED.is_totp_enabled").
Set("modified_at = EXCLUDED.modified_at").
Exec(ctx)
if err != nil {
return nil, fmt.Errorf("failed to upsert partner: %v", err)
}
CreatePartnerAuditEvent(ctx, s.al, AuditActionUpsert, partner.GetMetadata().GetName(), p.ID)
return &systemv3.Partner{
Metadata: &commonv3.Metadata{
Name: p.Name,
Description: p.Description,
},
Spec: &systemv3.PartnerSpec{
Host: p.Host,
Domain: p.Domain,
TosLink: p.TosLink,
LogoLink: p.LogoLink,
NotificationEmail: p.NotificationEmail,
HelpdeskEmail: p.HelpdeskEmail,
ProductName: p.ProductName,
SupportTeamName: p.SupportTeamName,
OpsHost: p.OpsHost,
FavIconLink: p.FavIconLink,
IsTOTPEnabled: p.IsTOTPEnabled,
},
}, nil
}