mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-06 19:36:41 +00:00
feat: project view (#90)
* init for views (spooler, handler) * init for views (spooler, handler) * start view in management * granted project * implement granted project view * search granted projects * fix search column * update all projects on project change * search roles * filter org * project members * project grant members * fix tests * application view * project grant search * mock * test appendevents * test appendevents * Update internal/view/query.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/eventstore/spooler/spooler.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/view/query.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * merge request changes * Update internal/project/repository/view/model/application.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * merge request changes * Project view sql (#92) * sql and configs * error handling * sql start in eventstore * on error handling, config * read user on members * Update internal/project/repository/view/application_view.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/application_query.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_grant_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_grant_member_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_grant_member_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_member_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_member_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/granted_project.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * return caos errors * Update internal/project/repository/view/model/granted_project_query.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_grant_member.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_grant_member_query.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_member.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_member_query.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_role.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/project/repository/view/model/project_role_query.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/application_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/application_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update pkg/management/api/grpc/project_converter.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * converter fix Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
handler
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
applicationTable = "management.applications"
|
||||
)
|
||||
|
||||
func (p *Application) MinimumCycleDuration() time.Duration { return p.cycleDuration }
|
||||
|
||||
func (p *Application) ViewModel() string {
|
||||
return applicationTable
|
||||
}
|
||||
|
||||
func (p *Application) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := p.view.GetLatestApplicationSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.ProjectQuery(sequence), nil
|
||||
}
|
||||
|
||||
func (p *Application) Process(event *models.Event) (err error) {
|
||||
app := new(view_model.ApplicationView)
|
||||
switch event.Type {
|
||||
case es_model.ApplicationAdded:
|
||||
app.AppendEvent(event)
|
||||
case es_model.ApplicationChanged,
|
||||
es_model.OIDCConfigAdded,
|
||||
es_model.OIDCConfigChanged,
|
||||
es_model.ApplicationDeactivated,
|
||||
es_model.ApplicationReactivated:
|
||||
err := app.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app, err = p.view.ApplicationByID(app.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.AppendEvent(event)
|
||||
case es_model.ApplicationRemoved:
|
||||
err := app.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.DeleteApplication(app.ID, event.Sequence)
|
||||
default:
|
||||
return p.view.ProcessedApplicationSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutApplication(app)
|
||||
}
|
||||
|
||||
func (p *Application) OnError(event *models.Event, soolerError error) error {
|
||||
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(soolerError).Warn("something went wrong in project app handler")
|
||||
return spooler.HandleError(event, p.view.GetLatestApplicationFailedEvent, p.view.ProcessedApplicationFailedEvent, p.view.ProcessedApplicationSequence, p.errorCountUntilSkip)
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
)
|
||||
|
||||
type GrantedProject struct {
|
||||
handler
|
||||
eventstore eventstore.Eventstore
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
grantedProjectTable = "management.granted_projects"
|
||||
)
|
||||
|
||||
func (p *GrantedProject) MinimumCycleDuration() time.Duration { return p.cycleDuration }
|
||||
|
||||
func (p *GrantedProject) ViewModel() string {
|
||||
return grantedProjectTable
|
||||
}
|
||||
|
||||
func (p *GrantedProject) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := p.view.GetLatestGrantedProjectSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.ProjectQuery(sequence), nil
|
||||
}
|
||||
|
||||
func (p *GrantedProject) Process(event *models.Event) (err error) {
|
||||
grantedProject := new(view_model.GrantedProjectView)
|
||||
switch event.Type {
|
||||
case es_model.ProjectAdded:
|
||||
grantedProject.AppendEvent(event)
|
||||
case es_model.ProjectChanged:
|
||||
grantedProject, err = p.view.GrantedProjectByIDs(event.AggregateID, event.ResourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = grantedProject.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.updateExistingProjects(grantedProject)
|
||||
case es_model.ProjectDeactivated, es_model.ProjectReactivated:
|
||||
grantedProject, err = p.view.GrantedProjectByIDs(event.AggregateID, event.ResourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = grantedProject.AppendEvent(event)
|
||||
case es_model.ProjectGrantAdded:
|
||||
err = grantedProject.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project, err := p.getProject(grantedProject.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantedProject.Name = project.Name
|
||||
//TODO: read org
|
||||
case es_model.ProjectGrantChanged:
|
||||
grant := new(view_model.ProjectGrant)
|
||||
err := grant.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantedProject, err = p.view.GrantedProjectByIDs(event.AggregateID, grant.GrantedOrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = grantedProject.AppendEvent(event)
|
||||
case es_model.ProjectGrantRemoved:
|
||||
grant := new(view_model.ProjectGrant)
|
||||
err := grant.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.DeleteGrantedProject(event.AggregateID, grant.GrantedOrgID, event.Sequence)
|
||||
default:
|
||||
return p.view.ProcessedGrantedProjectSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutGrantedProject(grantedProject)
|
||||
}
|
||||
|
||||
func (p *GrantedProject) getOrg(orgID string) {
|
||||
//TODO: Get Org
|
||||
}
|
||||
|
||||
func (p *GrantedProject) getProject(projectID string) (*model.Project, error) {
|
||||
return p.projectEvents.ProjectByID(context.Background(), projectID)
|
||||
}
|
||||
|
||||
func (p *GrantedProject) updateExistingProjects(project *view_model.GrantedProjectView) {
|
||||
projects, err := p.view.GrantedProjectsByID(project.ProjectID)
|
||||
if err != nil {
|
||||
logging.LogWithFields("SPOOL-los03", "id", project.ProjectID).WithError(err).Warn("could not update existing projects")
|
||||
}
|
||||
for _, existing := range projects {
|
||||
existing.Name = project.Name
|
||||
err := p.view.PutGrantedProject(existing)
|
||||
logging.LogWithFields("SPOOL-sjwi3", "id", existing.ProjectID).WithError(err).Warn("could not update existing project")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *GrantedProject) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-is8wa", "id", event.AggregateID).WithError(err).Warn("something went wrong in granted projecthandler")
|
||||
return spooler.HandleError(event, p.view.GetLatestGrantedProjectFailedEvent, p.view.ProcessedGrantedProjectFailedEvent, p.view.ProcessedGrantedProjectSequence, p.errorCountUntilSkip)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Configs map[string]*Config
|
||||
|
||||
type Config struct {
|
||||
MinimumCycleDurationMillisecond int
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
view *view.View
|
||||
bulkLimit uint64
|
||||
cycleDuration time.Duration
|
||||
errorCountUntilSkip uint64
|
||||
}
|
||||
|
||||
type EventstoreRepos struct {
|
||||
ProjectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos) []spooler.Handler {
|
||||
return []spooler.Handler{
|
||||
&GrantedProject{handler: handler{view, bulkLimit, configs.cycleDuration("GrantedProject"), errorCount}, eventstore: eventstore, projectEvents: repos.ProjectEvents},
|
||||
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
|
||||
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount}},
|
||||
&ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount}},
|
||||
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}},
|
||||
}
|
||||
}
|
||||
|
||||
func (configs Configs) cycleDuration(viewModel string) time.Duration {
|
||||
c, ok := configs[viewModel]
|
||||
if !ok {
|
||||
return 1 * time.Second
|
||||
}
|
||||
return time.Duration(c.MinimumCycleDurationMillisecond) * time.Millisecond
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProjectGrantMember struct {
|
||||
handler
|
||||
userEvents *usr_event.UserEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
projectGrantMemberTable = "management.project_grant_members"
|
||||
)
|
||||
|
||||
func (p *ProjectGrantMember) MinimumCycleDuration() time.Duration { return p.cycleDuration }
|
||||
|
||||
func (p *ProjectGrantMember) ViewModel() string {
|
||||
return projectGrantMemberTable
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := p.view.GetLatestProjectMemberSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(proj_es_model.ProjectAggregate, usr_es_model.UserAggregate).
|
||||
LatestSequenceFilter(sequence), nil
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) Process(event *models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case proj_es_model.ProjectAggregate:
|
||||
err = p.processProjectGrantMember(event)
|
||||
case usr_es_model.UserAggregate:
|
||||
err = p.processUser(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) processProjectGrantMember(event *models.Event) (err error) {
|
||||
member := new(view_model.ProjectGrantMemberView)
|
||||
switch event.Type {
|
||||
case proj_es_model.ProjectGrantMemberAdded:
|
||||
member.AppendEvent(event)
|
||||
p.fillData(member)
|
||||
case proj_es_model.ProjectGrantMemberChanged:
|
||||
err := member.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member, err = p.view.ProjectGrantMemberByIDs(member.GrantID, member.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.AppendEvent(event)
|
||||
case proj_es_model.ProjectGrantMemberRemoved:
|
||||
err := member.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.DeleteProjectGrantMember(event.AggregateID, member.UserID, event.Sequence)
|
||||
default:
|
||||
return p.view.ProcessedProjectGrantMemberSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutProjectGrantMember(member, member.Sequence)
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case usr_es_model.UserProfileChanged,
|
||||
usr_es_model.UserEmailChanged:
|
||||
members, err := p.view.ProjectGrantMembersByUserID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, member := range members {
|
||||
p.fillUserData(member, user)
|
||||
err = p.view.PutProjectGrantMember(member, event.Sequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return p.view.ProcessedProjectGrantMemberSequence(event.Sequence)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView) (err error) {
|
||||
user, err := p.userEvents.UserByID(context.Background(), member.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.fillUserData(member, user)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberView, user *usr_model.User) {
|
||||
member.UserName = user.UserName
|
||||
member.FirstName = user.FirstName
|
||||
member.LastName = user.LastName
|
||||
member.Email = user.EmailAddress
|
||||
}
|
||||
|
||||
func (p *ProjectGrantMember) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-kls93", "id", event.AggregateID).WithError(err).Warn("something went wrong in projectmember handler")
|
||||
return spooler.HandleError(event, p.view.GetLatestProjectGrantMemberFailedEvent, p.view.ProcessedProjectGrantMemberFailedEvent, p.view.ProcessedProjectGrantMemberSequence, p.errorCountUntilSkip)
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProjectMember struct {
|
||||
handler
|
||||
userEvents *usr_event.UserEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
projectMemberTable = "management.project_members"
|
||||
)
|
||||
|
||||
func (p *ProjectMember) MinimumCycleDuration() time.Duration { return p.cycleDuration }
|
||||
|
||||
func (p *ProjectMember) ViewModel() string {
|
||||
return projectMemberTable
|
||||
}
|
||||
|
||||
func (p *ProjectMember) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := p.view.GetLatestProjectMemberSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(proj_es_model.ProjectAggregate, usr_es_model.UserAggregate).
|
||||
LatestSequenceFilter(sequence), nil
|
||||
}
|
||||
|
||||
func (p *ProjectMember) Process(event *models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case proj_es_model.ProjectAggregate:
|
||||
err = p.processProjectMember(event)
|
||||
case usr_es_model.UserAggregate:
|
||||
err = p.processUser(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ProjectMember) processProjectMember(event *models.Event) (err error) {
|
||||
member := new(view_model.ProjectMemberView)
|
||||
switch event.Type {
|
||||
case proj_es_model.ProjectMemberAdded:
|
||||
member.AppendEvent(event)
|
||||
p.fillData(member)
|
||||
case proj_es_model.ProjectMemberChanged:
|
||||
err := member.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member, err = p.view.ProjectMemberByIDs(event.AggregateID, member.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.AppendEvent(event)
|
||||
case proj_es_model.ProjectMemberRemoved:
|
||||
err := member.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.DeleteProjectMember(event.AggregateID, member.UserID, event.Sequence)
|
||||
default:
|
||||
return p.view.ProcessedProjectMemberSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutProjectMember(member, member.Sequence)
|
||||
}
|
||||
|
||||
func (p *ProjectMember) processUser(event *models.Event) (err error) {
|
||||
switch event.Type {
|
||||
case usr_es_model.UserProfileChanged,
|
||||
usr_es_model.UserEmailChanged:
|
||||
members, err := p.view.ProjectMembersByUserID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, member := range members {
|
||||
p.fillUserData(member, user)
|
||||
err = p.view.PutProjectMember(member, event.Sequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return p.view.ProcessedProjectMemberSequence(event.Sequence)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectMember) fillData(member *view_model.ProjectMemberView) (err error) {
|
||||
user, err := p.userEvents.UserByID(context.Background(), member.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.fillUserData(member, user)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user *usr_model.User) {
|
||||
member.UserName = user.UserName
|
||||
member.FirstName = user.FirstName
|
||||
member.LastName = user.LastName
|
||||
member.Email = user.EmailAddress
|
||||
}
|
||||
func (p *ProjectMember) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in projectmember handler")
|
||||
return spooler.HandleError(event, p.view.GetLatestProjectMemberFailedEvent, p.view.ProcessedProjectMemberFailedEvent, p.view.ProcessedProjectMemberSequence, p.errorCountUntilSkip)
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProjectRole struct {
|
||||
handler
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
projectRoleTable = "management.project_roles"
|
||||
)
|
||||
|
||||
func (p *ProjectRole) MinimumCycleDuration() time.Duration { return p.cycleDuration }
|
||||
|
||||
func (p *ProjectRole) ViewModel() string {
|
||||
return projectRoleTable
|
||||
}
|
||||
|
||||
func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := p.view.GetLatestProjectRoleSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.ProjectQuery(sequence), nil
|
||||
}
|
||||
|
||||
func (p *ProjectRole) Process(event *models.Event) (err error) {
|
||||
role := new(view_model.ProjectRoleView)
|
||||
switch event.Type {
|
||||
case es_model.ProjectRoleAdded:
|
||||
role.AppendEvent(event)
|
||||
case es_model.ProjectRoleChanged:
|
||||
err := role.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role, err = p.view.ProjectRoleByIDs(event.AggregateID, event.ResourceOwner, role.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role.AppendEvent(event)
|
||||
case es_model.ProjectRoleRemoved:
|
||||
err := role.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = p.removeRoleFromAllResourceowners(event, role)
|
||||
case es_model.ProjectGrantAdded:
|
||||
return p.addGrantRoles(event)
|
||||
case es_model.ProjectGrantChanged:
|
||||
err = p.removeRolesFromResourceowner(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.addGrantRoles(event)
|
||||
case es_model.ProjectGrantRemoved:
|
||||
return p.removeRolesFromResourceowner(event)
|
||||
default:
|
||||
return p.view.ProcessedProjectRoleSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.view.PutProjectRole(role)
|
||||
}
|
||||
|
||||
func (p *ProjectRole) removeRoleFromAllResourceowners(event *models.Event, role *view_model.ProjectRoleView) error {
|
||||
roles, err := p.view.ResourceOwnerProjectRolesByKey(event.AggregateID, event.ResourceOwner, role.Key)
|
||||
if err != nil {
|
||||
logging.LogWithFields("HANDL-slo03", "aggregateID", event.AggregateID, "ResourceOwner", event.ResourceOwner, "Key", role.Key).WithError(err).Warn("could not read roles to remove")
|
||||
return err
|
||||
}
|
||||
for _, r := range roles {
|
||||
err = p.view.DeleteProjectRole(r.ProjectID, r.OrgID, r.Key, event.Sequence)
|
||||
if err != nil {
|
||||
logging.LogWithFields("HANDL-kloa2", "aggregateID", event.AggregateID, "ResourceOwner", event.ResourceOwner, "OrgID", r.OrgID, "Key", role.Key).WithError(err).Warn("could not remove role")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectRole) removeRolesFromResourceowner(event *models.Event) error {
|
||||
roles, err := p.view.ResourceOwnerProjectRoles(event.AggregateID, event.ResourceOwner)
|
||||
if err != nil {
|
||||
logging.LogWithFields("HANDL-slo03", "aggregateID", event.AggregateID, "ResourceOwner", event.ResourceOwner, "Key").WithError(err).Warn("could not read roles to remove")
|
||||
return err
|
||||
}
|
||||
for _, r := range roles {
|
||||
err = p.view.DeleteProjectRole(r.ProjectID, r.OrgID, r.Key, event.Sequence)
|
||||
if err != nil {
|
||||
logging.LogWithFields("HANDL-kloa2", "aggregateID", event.AggregateID, "ResourceOwner", event.ResourceOwner, "OrgID", r.OrgID).WithError(err).Warn("could not remove role")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectRole) addGrantRoles(event *models.Event) error {
|
||||
project, err := p.projectEvents.ProjectByID(context.Background(), event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grant := new(view_model.ProjectGrant)
|
||||
err = grant.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, roleKey := range grant.RoleKeys {
|
||||
role := getRoleFromProject(roleKey, project)
|
||||
projectRole := &view_model.ProjectRoleView{
|
||||
OrgID: grant.GrantedOrgID,
|
||||
ProjectID: event.AggregateID,
|
||||
Key: roleKey,
|
||||
DisplayName: role.DisplayName,
|
||||
Group: role.Group,
|
||||
ResourceOwner: event.ResourceOwner,
|
||||
CreationDate: event.CreationDate,
|
||||
Sequence: event.Sequence,
|
||||
}
|
||||
err := p.view.PutProjectRole(projectRole)
|
||||
logging.LogWithFields("HANDL-sj3TG", "eventID", event.ID).OnError(err).Warn("could not save project role")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRoleFromProject(roleKey string, project *proj_model.Project) *proj_model.ProjectRole {
|
||||
for _, role := range project.Roles {
|
||||
if roleKey == role.Key {
|
||||
return role
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ProjectRole) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
|
||||
return spooler.HandleError(event, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
|
||||
}
|
||||
Reference in New Issue
Block a user