Skip to content

Commit

Permalink
feat: preferences should reflect instantly after update (#381)
Browse files Browse the repository at this point in the history
- currently after modifying a preference(like a platform configuration)
application restart is required, this will no longer be a requirement
- updated go version to 1.21

Signed-off-by: Kush Sharma <[email protected]>
  • Loading branch information
kushsharma authored Oct 11, 2023
1 parent 0d062bb commit f1c11b8
Show file tree
Hide file tree
Showing 39 changed files with 816 additions and 590 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ jobs:
steps:
- uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.21'
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.52.2
version: v1.54.2
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
go-version: "1.21"
- name: Login to DockerHub
uses: docker/login-action@v1
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
go-version: "1.21"
- name: Login to DockerHub
uses: docker/login-action@v1
with:
Expand All @@ -41,7 +41,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
go-version: "1.21"
- name: Login to DockerHub
uses: docker/login-action@v1
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.21'
- name: install dependencies
run: go mod tidy
- name: run unit tests
Expand All @@ -42,7 +42,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.21'
- name: install dependencies
run: go mod tidy
- name: install spicedb binary
Expand All @@ -65,7 +65,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.21'
- name: install dependencies
run: go mod tidy
- name: run regression tests
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ lint-fix:
test: ## Run tests
@go test -race $(shell go list ./... | grep -v /ui | grep -v /vendor/ | grep -v /test/) -coverprofile=coverage.out -count 2 -timeout 150s

test-all: test e2e-smoke-test e2e-regression-test lint ## Run all tests
test-all: lint test e2e-smoke-test e2e-regression-test ## Run all tests

e2e-test: ## Run all e2e tests
## run `docker network prune` if docker fails to find non-overlapping ipv4 address pool
Expand Down
69 changes: 23 additions & 46 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func StartServer(logger *log.Zap, cfg *config.Frontier) error {
return err
}

deps, err := buildAPIDependencies(ctx, logger, cfg, resourceBlobRepository, dbClient, spiceDBClient)
deps, err := buildAPIDependencies(logger, cfg, resourceBlobRepository, dbClient, spiceDBClient)
if err != nil {
return err
}
Expand Down Expand Up @@ -162,7 +162,6 @@ func StartServer(logger *log.Zap, cfg *config.Frontier) error {
}

func buildAPIDependencies(
ctx context.Context,
logger log.Logger,
cfg *config.Frontier,
resourceBlobRepository *blob.ResourcesRepository,
Expand All @@ -171,13 +170,6 @@ func buildAPIDependencies(
) (api.Deps, error) {
preferenceService := preference.NewService(postgres.NewPreferenceRepository(dbc))

// load and apply config from preferences database or use default values for platform wide configs
cfgMap, err := preferenceService.LoadPlatformPreferences(ctx)
if err != nil {
return api.Deps{}, fmt.Errorf("failed to load platform preferences: %w", err)
}
applyPlatformPreference(logger, cfg, cfgMap)

var tokenKeySet jwk.Set
if len(cfg.App.Authentication.Token.RSAPath) > 0 {
if ks, err := jwk.ReadFile(cfg.App.Authentication.Token.RSAPath); err != nil {
Expand Down Expand Up @@ -256,7 +248,7 @@ func buildAPIDependencies(

organizationRepository := postgres.NewOrganizationRepository(dbc)
organizationService := organization.NewService(organizationRepository, relationService, userService,
authnService, policyService, cfg.App.DisableOrgsOnCreate)
authnService, policyService, preferenceService)

domainRepository := postgres.NewDomainRepository(logger, dbc)
domainService := domain.NewService(logger, domainRepository, userService, organizationService)
Expand All @@ -278,7 +270,7 @@ func buildAPIDependencies(
)

invitationService := invitation.NewService(mailDialer, postgres.NewInvitationRepository(logger, dbc),
organizationService, groupService, userService, relationService, policyService, cfg.App.Invite)
organizationService, groupService, userService, relationService, policyService, preferenceService)
cascadeDeleter := deleter.NewCascadeDeleter(organizationService, projectService, resourceService,
groupService, policyService, roleService, invitationService, userService)

Expand All @@ -295,29 +287,26 @@ func buildAPIDependencies(
auditService := audit.NewService("frontier", auditRepository)

dependencies := api.Deps{
DisableOrgsListing: cfg.App.DisableOrgsListing,
DisableUsersListing: cfg.App.DisableUsersListing,
DisableOrgOnCreate: cfg.App.DisableOrgsOnCreate,
OrgService: organizationService,
ProjectService: projectService,
GroupService: groupService,
RoleService: roleService,
PolicyService: policyService,
UserService: userService,
NamespaceService: namespaceService,
PermissionService: permissionService,
RelationService: relationService,
ResourceService: resourceService,
SessionService: sessionService,
AuthnService: authnService,
DeleterService: cascadeDeleter,
MetaSchemaService: metaschemaService,
BootstrapService: bootstrapService,
InvitationService: invitationService,
ServiceUserService: serviceUserService,
AuditService: auditService,
DomainService: domainService,
PreferenceService: preferenceService,
OrgService: organizationService,
ProjectService: projectService,
GroupService: groupService,
RoleService: roleService,
PolicyService: policyService,
UserService: userService,
NamespaceService: namespaceService,
PermissionService: permissionService,
RelationService: relationService,
ResourceService: resourceService,
SessionService: sessionService,
AuthnService: authnService,
DeleterService: cascadeDeleter,
MetaSchemaService: metaschemaService,
BootstrapService: bootstrapService,
InvitationService: invitationService,
ServiceUserService: serviceUserService,
AuditService: auditService,
DomainService: domainService,
PreferenceService: preferenceService,
}
return dependencies, nil
}
Expand Down Expand Up @@ -357,15 +346,3 @@ func setupDB(cfg db.Config, logger log.Logger) (dbc *db.Client, err error) {

return
}

// applyPlatformPreference applies platform wide preferences to server config
// if preference is not set in database it will use default value
func applyPlatformPreference(logger log.Logger, cfg *config.Frontier, cfgMap map[string]string) {
cfg.App.DisableOrgsOnCreate = cfgMap[preference.PlatformDisableOrgsOnCreate] == "true"
cfg.App.DisableOrgsListing = cfgMap[preference.PlatformDisableOrgsListing] == "true"
cfg.App.DisableUsersListing = cfgMap[preference.PlatformDisableUsersListing] == "true"
cfg.App.Invite.WithRoles = cfgMap[preference.PlatformInviteWithRoles] == "true"

cfg.App.Invite.MailTemplate.Body = cfgMap[preference.PlatformInviteMailBody]
cfg.App.Invite.MailTemplate.Subject = cfgMap[preference.PlatformInviteMailSubject]
}
65 changes: 46 additions & 19 deletions core/invitation/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ import (
"fmt"
"html/template"

"github.com/raystack/frontier/pkg/logger"
"go.uber.org/zap"

"github.com/mcuadros/go-defaults"
"github.com/raystack/frontier/core/authenticate"
"github.com/raystack/frontier/core/policy"
"github.com/raystack/frontier/core/preference"
"gopkg.in/mail.v2"

"github.com/raystack/frontier/pkg/mailer"
Expand Down Expand Up @@ -55,6 +60,10 @@ type PolicyService interface {
Create(ctx context.Context, policy policy.Policy) (policy.Policy, error)
}

type PreferencesService interface {
LoadPlatformPreferences(ctx context.Context) (map[string]string, error)
}

type Service struct {
dialer mailer.Dialer
repo Repository
Expand All @@ -63,13 +72,13 @@ type Service struct {
userService UserService
relationService RelationService
policyService PolicyService
config Config
prefService PreferencesService
}

func NewService(dialer mailer.Dialer, repo Repository,
orgSvc OrganizationService, grpSvc GroupService,
userService UserService, relService RelationService,
policyService PolicyService, config Config) *Service {
policyService PolicyService, prefService PreferencesService) *Service {
return &Service{
dialer: dialer,
repo: repo,
Expand All @@ -78,7 +87,7 @@ func NewService(dialer mailer.Dialer, repo Repository,
userService: userService,
relationService: relService,
policyService: policyService,
config: config,
prefService: prefService,
}
}

Expand All @@ -94,11 +103,26 @@ func (s Service) Get(ctx context.Context, id uuid.UUID) (Invitation, error) {
return s.repo.Get(ctx, id)
}

func (s Service) getConfig(ctx context.Context) *Config {
c := &Config{}
defaults.SetDefaults(c)
prefs, err := s.prefService.LoadPlatformPreferences(ctx)
if err != nil {
logger.Ctx(ctx).Error("failed to load platform preferences for invitation", zap.Error(err))
// don't fail
}
c.WithRoles = prefs[preference.PlatformInviteWithRoles] == "true"
c.MailTemplate.Subject = prefs[preference.PlatformInviteMailSubject]
c.MailTemplate.Body = prefs[preference.PlatformInviteMailBody]
return c
}

func (s Service) Create(ctx context.Context, invitation Invitation) (Invitation, error) {
if invitation.ID == uuid.Nil {
invitation.ID = uuid.New()
}
if !s.config.WithRoles {
conf := s.getConfig(ctx)
if !conf.WithRoles {
// clear roles if not allowed at instance level
invitation.RoleIDs = nil
}
Expand All @@ -121,7 +145,7 @@ func (s Service) Create(ctx context.Context, invitation Invitation) (Invitation,
}

// notify user
t, err := template.New("body").Parse(s.config.MailTemplate.Body)
t, err := template.New("body").Parse(conf.MailTemplate.Body)
if err != nil {
return Invitation{}, fmt.Errorf("failed to parse email template: %w", err)
}
Expand All @@ -139,7 +163,7 @@ func (s Service) Create(ctx context.Context, invitation Invitation) (Invitation,
msg := mail.NewMessage()
msg.SetHeader("From", s.dialer.FromHeader())
msg.SetHeader("To", invitation.UserID)
msg.SetHeader("Subject", s.config.MailTemplate.Subject)
msg.SetHeader("Subject", conf.MailTemplate.Subject)
msg.SetBody("text/html", tpl.String())
if err := s.dialer.DialAndSend(msg); err != nil {
return invitation, err
Expand Down Expand Up @@ -263,20 +287,23 @@ func (s Service) Accept(ctx context.Context, id uuid.UUID) error {

// check if invitation has a list of roles which we want to assign to the user at org level
var roleErr error
if len(invite.RoleIDs) > 0 && s.config.WithRoles {
for _, inviteRoleID := range invite.RoleIDs {
if _, err := s.policyService.Create(ctx, policy.Policy{
RoleID: inviteRoleID,
ResourceID: invite.OrgID,
ResourceType: schema.OrganizationNamespace,
PrincipalID: user.ID,
PrincipalType: schema.UserPrincipal,
}); err != nil {
roleErr = errors.Join(roleErr, err)
if len(invite.RoleIDs) > 0 {
conf := s.getConfig(ctx)
if conf.WithRoles {
for _, inviteRoleID := range invite.RoleIDs {
if _, err := s.policyService.Create(ctx, policy.Policy{
RoleID: inviteRoleID,
ResourceID: invite.OrgID,
ResourceType: schema.OrganizationNamespace,
PrincipalID: user.ID,
PrincipalType: schema.UserPrincipal,
}); err != nil {
roleErr = errors.Join(roleErr, err)
}
}
if roleErr != nil {
return roleErr
}
}
if roleErr != nil {
return roleErr
}
}

Expand Down
Loading

0 comments on commit f1c11b8

Please sign in to comment.