fix: projects (#221)

* feat: projects and project grants seperated

* fix: tests

* fix: add mock
This commit is contained in:
Fabi
2020-06-15 14:50:39 +02:00
committed by GitHub
parent c4eaeee7af
commit e63179514c
33 changed files with 4425 additions and 3666 deletions

View File

@@ -41,33 +41,33 @@ func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*pro
return repo.ProjectEvents.ReactivateProject(ctx, id)
}
func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *proj_model.GrantedProjectSearchRequest) (*proj_model.GrantedProjectSearchResponse, error) {
func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model.ProjectViewSearchRequest) (*proj_model.ProjectViewSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
permissions := auth.GetPermissionsFromCtx(ctx)
if !auth.HasGlobalPermission(permissions) {
ids := auth.GetPermissionCtxIDs(permissions)
request.Queries = append(request.Queries, &proj_model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IN, Value: ids})
request.Queries = append(request.Queries, &proj_model.ProjectViewSearchQuery{Key: proj_model.PROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IN, Value: ids})
}
projects, count, err := repo.View.SearchGrantedProjects(request)
projects, count, err := repo.View.SearchProjects(request)
if err != nil {
return nil, err
}
return &proj_model.GrantedProjectSearchResponse{
return &proj_model.ProjectViewSearchResponse{
Offset: request.Offset,
Limit: request.Limit,
TotalResult: uint64(count),
Result: model.GrantedProjectsToModel(projects),
Result: model.ProjectsToModel(projects),
}, nil
}
func (repo *ProjectRepo) GetGrantedProjectGrantByIDs(ctx context.Context, projectID, grantID string) (project *proj_model.GrantedProjectView, err error) {
p, err := repo.View.GrantedProjectGrantByIDs(projectID, grantID)
func (repo *ProjectRepo) ProjectGrantViewByID(ctx context.Context, grantID string) (project *proj_model.ProjectGrantView, err error) {
p, err := repo.View.ProjectGrantByID(grantID)
if err != nil {
return nil, err
}
return model.GrantedProjectToModel(p), nil
return model.ProjectGrantToModel(p), nil
}
func (repo *ProjectRepo) ProjectMemberByID(ctx context.Context, projectID, userID string) (member *proj_model.ProjectMember, err error) {
@@ -180,6 +180,20 @@ func (repo *ProjectRepo) ProjectGrantByID(ctx context.Context, projectID, appID
return repo.ProjectEvents.ProjectGrantByIDs(ctx, projectID, appID)
}
func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_model.ProjectGrantViewSearchRequest) (*proj_model.ProjectGrantViewSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
projects, count, err := repo.View.SearchProjectGrants(request)
if err != nil {
return nil, err
}
return &proj_model.ProjectGrantViewSearchResponse{
Offset: request.Offset,
Limit: request.Limit,
TotalResult: uint64(count),
Result: model.ProjectGrantsToModel(projects),
}, nil
}
func (repo *ProjectRepo) AddProjectGrant(ctx context.Context, app *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.AddProjectGrant(ctx, app)
}

View File

@@ -33,7 +33,8 @@ type EventstoreRepos struct {
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, orgEvents: repos.OrgEvents},
&Project{handler: handler{view, bulkLimit, configs.cycleDuration("Project"), errorCount}, eventstore: eventstore},
&ProjectGrant{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrant"), errorCount}, eventstore: eventstore, projectEvents: repos.ProjectEvents, orgEvents: repos.OrgEvents},
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount}, userEvents: repos.UserEvents},
&ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount}, userEvents: repos.UserEvents},

View File

@@ -0,0 +1,64 @@
package handler
import (
"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"
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 Project struct {
handler
eventstore eventstore.Eventstore
}
const (
projectTable = "management.projects"
)
func (p *Project) MinimumCycleDuration() time.Duration { return p.cycleDuration }
func (p *Project) ViewModel() string {
return projectTable
}
func (p *Project) EventQuery() (*models.SearchQuery, error) {
sequence, err := p.view.GetLatestProjectSequence()
if err != nil {
return nil, err
}
return proj_event.ProjectQuery(sequence), nil
}
func (p *Project) Process(event *models.Event) (err error) {
project := new(view_model.ProjectView)
switch event.Type {
case es_model.ProjectAdded:
project.AppendEvent(event)
case es_model.ProjectChanged,
es_model.ProjectDeactivated,
es_model.ProjectReactivated:
project, err = p.view.ProjectByID(event.AggregateID)
if err != nil {
return err
}
err = project.AppendEvent(event)
default:
return p.view.ProcessedProjectSequence(event.Sequence)
}
if err != nil {
return err
}
return p.view.PutProject(project)
}
func (p *Project) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-dLsop3", "id", event.AggregateID).WithError(err).Warn("something went wrong in projecthandler")
return spooler.HandleError(event, err, p.view.GetLatestProjectFailedEvent, p.view.ProcessedProjectFailedEvent, p.view.ProcessedProjectSequence, p.errorCountUntilSkip)
}

View File

@@ -17,7 +17,7 @@ import (
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
type GrantedProject struct {
type ProjectGrant struct {
handler
eventstore eventstore.Eventstore
projectEvents *proj_event.ProjectEventstore
@@ -25,44 +25,32 @@ type GrantedProject struct {
}
const (
grantedProjectTable = "management.granted_projects"
grantedProjectTable = "management.project_grants"
)
func (p *GrantedProject) MinimumCycleDuration() time.Duration { return p.cycleDuration }
func (p *ProjectGrant) MinimumCycleDuration() time.Duration { return p.cycleDuration }
func (p *GrantedProject) ViewModel() string {
func (p *ProjectGrant) ViewModel() string {
return grantedProjectTable
}
func (p *GrantedProject) EventQuery() (*models.SearchQuery, error) {
sequence, err := p.view.GetLatestGrantedProjectSequence()
func (p *ProjectGrant) EventQuery() (*models.SearchQuery, error) {
sequence, err := p.view.GetLatestProjectGrantSequence()
if err != nil {
return nil, err
}
return proj_event.ProjectQuery(sequence), nil
}
func (p *GrantedProject) Process(event *models.Event) (err error) {
grantedProject := new(view_model.GrantedProjectView)
func (p *ProjectGrant) Process(event *models.Event) (err error) {
grantedProject := new(view_model.ProjectGrantView)
switch event.Type {
case es_model.ProjectAdded:
grantedProject.AppendEvent(event)
case es_model.ProjectChanged:
grantedProject, err = p.view.GrantedProjectByIDs(event.AggregateID, event.ResourceOwner)
project, err := p.view.ProjectByID(event.AggregateID)
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)
p.updateExistingProjects(project)
case es_model.ProjectGrantAdded:
err = grantedProject.AppendEvent(event)
if err != nil {
@@ -85,7 +73,7 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
if err != nil {
return err
}
grantedProject, err = p.view.GrantedProjectByIDs(event.AggregateID, grant.GrantedOrgID)
grantedProject, err = p.view.ProjectGrantByID(grant.GrantID)
if err != nil {
return err
}
@@ -96,38 +84,38 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
if err != nil {
return err
}
return p.view.DeleteGrantedProject(event.AggregateID, grant.GrantedOrgID, event.Sequence)
return p.view.DeleteProjectGrant(grant.GrantID, event.Sequence)
default:
return p.view.ProcessedGrantedProjectSequence(event.Sequence)
return p.view.ProcessedProjectGrantSequence(event.Sequence)
}
if err != nil {
return err
}
return p.view.PutGrantedProject(grantedProject)
return p.view.PutProjectGrant(grantedProject)
}
func (p *GrantedProject) fillOrgData(grantedProject *view_model.GrantedProjectView, org *org_model.Org) {
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org *org_model.Org) {
grantedProject.OrgDomain = org.Domain
grantedProject.OrgName = org.Name
}
func (p *GrantedProject) getProject(projectID string) (*proj_model.Project, error) {
func (p *ProjectGrant) getProject(projectID string) (*proj_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)
func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView) {
projects, err := p.view.ProjectGrantsByProjectID(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)
err := p.view.PutProjectGrant(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 {
func (p *ProjectGrant) 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, err, p.view.GetLatestGrantedProjectFailedEvent, p.view.ProcessedGrantedProjectFailedEvent, p.view.ProcessedGrantedProjectSequence, p.errorCountUntilSkip)
return spooler.HandleError(event, err, p.view.GetLatestProjectGrantFailedEvent, p.view.ProcessedProjectGrantFailedEvent, p.view.ProcessedProjectGrantSequence, p.errorCountUntilSkip)
}

View File

@@ -1,60 +0,0 @@
package view
import (
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
global_view "github.com/caos/zitadel/internal/view"
)
const (
grantedProjectTable = "management.granted_projects"
)
func (v *View) GrantedProjectByIDs(projectID, orgID string) (*model.GrantedProjectView, error) {
return view.GrantedProjectByIDs(v.Db, grantedProjectTable, projectID, orgID)
}
func (v *View) GrantedProjectGrantByIDs(projectID, grantID string) (*model.GrantedProjectView, error) {
return view.GrantedProjectGrantByIDs(v.Db, grantedProjectTable, projectID, grantID)
}
func (v *View) GrantedProjectsByID(projectID string) ([]*model.GrantedProjectView, error) {
return view.GrantedProjectsByID(v.Db, grantedProjectTable, projectID)
}
func (v *View) SearchGrantedProjects(request *proj_model.GrantedProjectSearchRequest) ([]*model.GrantedProjectView, int, error) {
return view.SearchGrantedProjects(v.Db, grantedProjectTable, request)
}
func (v *View) PutGrantedProject(project *model.GrantedProjectView) error {
err := view.PutGrantedProject(v.Db, grantedProjectTable, project)
if err != nil {
return err
}
return v.ProcessedGrantedProjectSequence(project.Sequence)
}
func (v *View) DeleteGrantedProject(projectID, orgID string, eventSequence uint64) error {
err := view.DeleteGrantedProject(v.Db, grantedProjectTable, projectID, orgID)
if err != nil {
return nil
}
return v.ProcessedGrantedProjectSequence(eventSequence)
}
func (v *View) GetLatestGrantedProjectSequence() (uint64, error) {
return v.latestSequence(grantedProjectTable)
}
func (v *View) ProcessedGrantedProjectSequence(eventSequence uint64) error {
return v.saveCurrentSequence(grantedProjectTable, eventSequence)
}
func (v *View) GetLatestGrantedProjectFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(grantedProjectTable, sequence)
}
func (v *View) ProcessedGrantedProjectFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@@ -0,0 +1,52 @@
package view
import (
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
global_view "github.com/caos/zitadel/internal/view"
)
const (
projectTable = "management.projects"
)
func (v *View) ProjectByID(projectID string) (*model.ProjectView, error) {
return view.ProjectByID(v.Db, projectTable, projectID)
}
func (v *View) SearchProjects(request *proj_model.ProjectViewSearchRequest) ([]*model.ProjectView, int, error) {
return view.SearchProjects(v.Db, projectTable, request)
}
func (v *View) PutProject(project *model.ProjectView) error {
err := view.PutProject(v.Db, projectTable, project)
if err != nil {
return err
}
return v.ProcessedProjectSequence(project.Sequence)
}
func (v *View) DeleteProject(projectID string, eventSequence uint64) error {
err := view.DeleteProject(v.Db, projectTable, projectID)
if err != nil {
return nil
}
return v.ProcessedProjectSequence(eventSequence)
}
func (v *View) GetLatestProjectSequence() (uint64, error) {
return v.latestSequence(projectTable)
}
func (v *View) ProcessedProjectSequence(eventSequence uint64) error {
return v.saveCurrentSequence(projectTable, eventSequence)
}
func (v *View) GetLatestProjectFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(projectTable, sequence)
}
func (v *View) ProcessedProjectFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@@ -0,0 +1,60 @@
package view
import (
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
global_view "github.com/caos/zitadel/internal/view"
)
const (
grantedProjectTable = "management.project_grants"
)
func (v *View) ProjectGrantByID(grantID string) (*model.ProjectGrantView, error) {
return view.ProjectGrantByID(v.Db, grantedProjectTable, grantID)
}
func (v *View) ProjectGrantByProjectAndOrg(projectID, orgID string) (*model.ProjectGrantView, error) {
return view.ProjectGrantByProjectAndOrg(v.Db, grantedProjectTable, projectID, orgID)
}
func (v *View) ProjectGrantsByProjectID(projectID string) ([]*model.ProjectGrantView, error) {
return view.ProjectGrantsByProjectID(v.Db, grantedProjectTable, projectID)
}
func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, int, error) {
return view.SearchProjectGrants(v.Db, grantedProjectTable, request)
}
func (v *View) PutProjectGrant(project *model.ProjectGrantView) error {
err := view.PutProjectGrant(v.Db, grantedProjectTable, project)
if err != nil {
return err
}
return v.ProcessedProjectGrantSequence(project.Sequence)
}
func (v *View) DeleteProjectGrant(grantID string, eventSequence uint64) error {
err := view.DeleteProjectGrant(v.Db, grantedProjectTable, grantID)
if err != nil {
return nil
}
return v.ProcessedProjectGrantSequence(eventSequence)
}
func (v *View) GetLatestProjectGrantSequence() (uint64, error) {
return v.latestSequence(grantedProjectTable)
}
func (v *View) ProcessedProjectGrantSequence(eventSequence uint64) error {
return v.saveCurrentSequence(grantedProjectTable, eventSequence)
}
func (v *View) GetLatestProjectGrantFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(grantedProjectTable, sequence)
}
func (v *View) ProcessedProjectGrantFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@@ -12,8 +12,9 @@ type ProjectRepository interface {
UpdateProject(ctx context.Context, project *model.Project) (*model.Project, error)
DeactivateProject(ctx context.Context, id string) (*model.Project, error)
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
SearchGrantedProjects(ctx context.Context, request *model.GrantedProjectSearchRequest) (*model.GrantedProjectSearchResponse, error)
GetGrantedProjectGrantByIDs(ctx context.Context, projectID, grantID string) (*model.GrantedProjectView, error)
SearchProjects(ctx context.Context, request *model.ProjectViewSearchRequest) (*model.ProjectViewSearchResponse, error)
SearchProjectGrants(ctx context.Context, request *model.ProjectGrantViewSearchRequest) (*model.ProjectGrantViewSearchResponse, error)
ProjectGrantViewByID(ctx context.Context, grantID string) (*model.ProjectGrantView, error)
ProjectMemberByID(ctx context.Context, projectID, userID string) (*model.ProjectMember, error)
AddProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)

View File

@@ -1,79 +0,0 @@
package model
import (
"github.com/caos/zitadel/internal/model"
"time"
)
type GrantedProjectView struct {
ProjectID string
Name string
CreationDate time.Time
ChangeDate time.Time
State ProjectState
Type ProjectType
ResourceOwner string
OrgID string
OrgName string
OrgDomain string
Sequence uint64
GrantID string
GrantedRoleKeys []string
}
type ProjectType int32
const (
PROJECTTYPE_OWNED ProjectType = iota
PROJECTTYPE_GRANTED
)
type GrantedProjectSearchRequest struct {
Offset uint64
Limit uint64
SortingColumn GrantedProjectSearchKey
Asc bool
Queries []*GrantedProjectSearchQuery
}
type GrantedProjectSearchKey int32
const (
GRANTEDPROJECTSEARCHKEY_UNSPECIFIED GrantedProjectSearchKey = iota
GRANTEDPROJECTSEARCHKEY_NAME
GRANTEDPROJECTSEARCHKEY_PROJECTID
GRANTEDPROJECTSEARCHKEY_GRANTID
GRANTEDPROJECTSEARCHKEY_ORGID
GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER
)
type GrantedProjectSearchQuery struct {
Key GrantedProjectSearchKey
Method model.SearchMethod
Value interface{}
}
type GrantedProjectSearchResponse struct {
Offset uint64
Limit uint64
TotalResult uint64
Result []*GrantedProjectView
}
func (r *GrantedProjectSearchRequest) AppendMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &GrantedProjectSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_ORGID, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}
func (r *GrantedProjectSearchRequest) AppendNotMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &GrantedProjectSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_ORGID, Method: model.SEARCHMETHOD_NOT_EQUALS, Value: orgID})
}
func (r *GrantedProjectSearchRequest) AppendMyResourceOwnerQuery(orgID string) {
r.Queries = append(r.Queries, &GrantedProjectSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}
func (r *GrantedProjectSearchRequest) EnsureLimit(limit uint64) {
if r.Limit == 0 || r.Limit > limit {
r.Limit = limit
}
}

View File

@@ -0,0 +1,71 @@
package model
import (
"github.com/caos/zitadel/internal/model"
"time"
)
type ProjectGrantView struct {
ProjectID string
Name string
CreationDate time.Time
ChangeDate time.Time
State ProjectState
ResourceOwner string
OrgID string
OrgName string
OrgDomain string
Sequence uint64
GrantID string
GrantedRoleKeys []string
}
type ProjectGrantViewSearchRequest struct {
Offset uint64
Limit uint64
SortingColumn ProjectGrantViewSearchKey
Asc bool
Queries []*ProjectGrantViewSearchQuery
}
type ProjectGrantViewSearchKey int32
const (
GRANTEDPROJECTSEARCHKEY_UNSPECIFIED ProjectGrantViewSearchKey = iota
GRANTEDPROJECTSEARCHKEY_NAME
GRANTEDPROJECTSEARCHKEY_PROJECTID
GRANTEDPROJECTSEARCHKEY_GRANTID
GRANTEDPROJECTSEARCHKEY_ORGID
GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER
)
type ProjectGrantViewSearchQuery struct {
Key ProjectGrantViewSearchKey
Method model.SearchMethod
Value interface{}
}
type ProjectGrantViewSearchResponse struct {
Offset uint64
Limit uint64
TotalResult uint64
Result []*ProjectGrantView
}
func (r *ProjectGrantViewSearchRequest) AppendMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_ORGID, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}
func (r *ProjectGrantViewSearchRequest) AppendNotMyOrgQuery(orgID string) {
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_ORGID, Method: model.SEARCHMETHOD_NOT_EQUALS, Value: orgID})
}
func (r *ProjectGrantViewSearchRequest) AppendMyResourceOwnerQuery(orgID string) {
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}
func (r *ProjectGrantViewSearchRequest) EnsureLimit(limit uint64) {
if r.Limit == 0 || r.Limit > limit {
r.Limit = limit
}
}

View File

@@ -0,0 +1,56 @@
package model
import (
"github.com/caos/zitadel/internal/model"
"time"
)
type ProjectView struct {
ProjectID string
Name string
CreationDate time.Time
ChangeDate time.Time
State ProjectState
ResourceOwner string
Sequence uint64
}
type ProjectViewSearchRequest struct {
Offset uint64
Limit uint64
SortingColumn ProjectViewSearchKey
Asc bool
Queries []*ProjectViewSearchQuery
}
type ProjectViewSearchKey int32
const (
PROJECTSEARCHKEY_UNSPECIFIED ProjectViewSearchKey = iota
PROJECTSEARCHKEY_NAME
PROJECTSEARCHKEY_PROJECTID
PROJECTSEARCHKEY_RESOURCE_OWNER
)
type ProjectViewSearchQuery struct {
Key ProjectViewSearchKey
Method model.SearchMethod
Value interface{}
}
type ProjectViewSearchResponse struct {
Offset uint64
Limit uint64
TotalResult uint64
Result []*ProjectView
}
func (r *ProjectViewSearchRequest) AppendMyResourceOwnerQuery(orgID string) {
r.Queries = append(r.Queries, &ProjectViewSearchQuery{Key: PROJECTSEARCHKEY_RESOURCE_OWNER, Method: model.SEARCHMETHOD_EQUALS, Value: orgID})
}
func (r *ProjectViewSearchRequest) EnsureLimit(limit uint64) {
if r.Limit == 0 || r.Limit > limit {
r.Limit = limit
}
}

View File

@@ -1,65 +0,0 @@
package view
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view"
"github.com/jinzhu/gorm"
)
func GrantedProjectByIDs(db *gorm.DB, table, projectID, orgID string) (*model.GrantedProjectView, error) {
project := new(model.GrantedProjectView)
projectIDQuery := model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS}
orgIDQuery := model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_ORGID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
query := view.PrepareGetByQuery(table, projectIDQuery, orgIDQuery)
err := query(db, project)
return project, err
}
func GrantedProjectGrantByIDs(db *gorm.DB, table, projectID, grantID string) (*model.GrantedProjectView, error) {
project := new(model.GrantedProjectView)
projectIDQuery := model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS}
grantIDQuery := model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_GRANTID, Value: grantID, Method: global_model.SEARCHMETHOD_EQUALS}
query := view.PrepareGetByQuery(table, projectIDQuery, grantIDQuery)
err := query(db, project)
return project, err
}
func GrantedProjectsByID(db *gorm.DB, table, projectID string) ([]*model.GrantedProjectView, error) {
projects := make([]*model.GrantedProjectView, 0)
queries := []*proj_model.GrantedProjectSearchQuery{
&proj_model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.GrantedProjectSearchRequest{Queries: queries})
_, err := query(db, &projects)
if err != nil {
return nil, err
}
return projects, nil
}
func SearchGrantedProjects(db *gorm.DB, table string, req *proj_model.GrantedProjectSearchRequest) ([]*model.GrantedProjectView, int, error) {
projects := make([]*model.GrantedProjectView, 0)
query := view.PrepareSearchQuery(table, model.GrantedProjectSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &projects)
if err != nil {
return nil, 0, err
}
return projects, count, nil
}
func PutGrantedProject(db *gorm.DB, table string, project *model.GrantedProjectView) error {
save := view.PrepareSave(table)
return save(db, project)
}
func DeleteGrantedProject(db *gorm.DB, table, projectID, orgID string) error {
project, err := GrantedProjectByIDs(db, table, projectID, orgID)
if err != nil {
return err
}
delete := view.PrepareDeleteByObject(table, project)
return delete(db)
}

View File

@@ -1,67 +0,0 @@
package model
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/view"
)
type GrantedProjectSearchRequest proj_model.GrantedProjectSearchRequest
type GrantedProjectSearchQuery proj_model.GrantedProjectSearchQuery
type GrantedProjectSearchKey proj_model.GrantedProjectSearchKey
func (req GrantedProjectSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req GrantedProjectSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req GrantedProjectSearchRequest) GetSortingColumn() view.ColumnKey {
if req.SortingColumn == proj_model.GRANTEDPROJECTSEARCHKEY_UNSPECIFIED {
return nil
}
return GrantedProjectSearchKey(req.SortingColumn)
}
func (req GrantedProjectSearchRequest) GetAsc() bool {
return req.Asc
}
func (req GrantedProjectSearchRequest) GetQueries() []view.SearchQuery {
result := make([]view.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = GrantedProjectSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req GrantedProjectSearchQuery) GetKey() view.ColumnKey {
return GrantedProjectSearchKey(req.Key)
}
func (req GrantedProjectSearchQuery) GetMethod() global_model.SearchMethod {
return req.Method
}
func (req GrantedProjectSearchQuery) GetValue() interface{} {
return req.Value
}
func (key GrantedProjectSearchKey) ToColumnName() string {
switch proj_model.GrantedProjectSearchKey(key) {
case proj_model.GRANTEDPROJECTSEARCHKEY_NAME:
return GrantedProjectKeyName
case proj_model.GRANTEDPROJECTSEARCHKEY_GRANTID:
return GrantedProjectKeyGrantID
case proj_model.GRANTEDPROJECTSEARCHKEY_ORGID:
return GrantedProjectKeyOrgID
case proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID:
return GrantedProjectKeyProjectID
case proj_model.GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER:
return GrantedProjectKeyResourceOwner
default:
return ""
}
}

View File

@@ -0,0 +1,108 @@
package model
import (
"encoding/json"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/project/model"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
"time"
)
const (
ProjectKeyProjectID = "project_id"
ProjectKeyResourceOwner = "resource_owner"
ProjectKeyName = "project_name"
)
type ProjectView struct {
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
Name string `json:"name" gorm:"column:project_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:project_state"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func ProjectFromModel(project *model.ProjectView) *ProjectView {
return &ProjectView{
ProjectID: project.ProjectID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: int32(project.State),
ResourceOwner: project.ResourceOwner,
Sequence: project.Sequence,
}
}
func ProjectToModel(project *ProjectView) *model.ProjectView {
return &model.ProjectView{
ProjectID: project.ProjectID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: model.ProjectState(project.State),
ResourceOwner: project.ResourceOwner,
Sequence: project.Sequence,
}
}
func ProjectsToModel(projects []*ProjectView) []*model.ProjectView {
result := make([]*model.ProjectView, len(projects))
for i, p := range projects {
result[i] = ProjectToModel(p)
}
return result
}
func (p *ProjectView) AppendEvent(event *models.Event) (err error) {
p.ChangeDate = event.CreationDate
p.Sequence = event.Sequence
switch event.Type {
case es_model.ProjectAdded:
p.State = int32(model.PROJECTSTATE_ACTIVE)
p.CreationDate = event.CreationDate
p.setRootData(event)
err = p.setData(event)
case es_model.ProjectChanged:
err = p.setData(event)
case es_model.ProjectDeactivated:
p.State = int32(model.PROJECTSTATE_INACTIVE)
case es_model.ProjectReactivated:
p.State = int32(model.PROJECTSTATE_ACTIVE)
}
return err
}
func (p *ProjectView) setRootData(event *models.Event) {
p.ProjectID = event.AggregateID
p.ResourceOwner = event.ResourceOwner
}
func (p *ProjectView) setData(event *models.Event) error {
if err := json.Unmarshal(event.Data, p); err != nil {
logging.Log("EVEN-dlo92").WithError(err).Error("could not unmarshal event data")
return err
}
return nil
}
func (p *ProjectView) setProjectData(event *models.Event) error {
project := new(ProjectView)
err := project.SetData(event)
if err != nil {
return err
}
return nil
}
func (p *ProjectView) SetData(event *models.Event) error {
if err := json.Unmarshal(event.Data, p); err != nil {
logging.Log("EVEN-sk9Sj").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-s9ols", "Could not unmarshal data")
}
return nil
}

View File

@@ -12,26 +12,25 @@ import (
)
const (
GrantedProjectKeyProjectID = "project_id"
GrantedProjectKeyGrantID = "grant_id"
GrantedProjectKeyOrgID = "org_id"
GrantedProjectKeyResourceOwner = "resource_owner"
GrantedProjectKeyName = "project_name"
ProjectGrantKeyProjectID = "project_id"
ProjectGrantKeyGrantID = "grant_id"
ProjectGrantKeyOrgID = "org_id"
ProjectGrantKeyResourceOwner = "resource_owner"
ProjectGrantKeyName = "project_name"
)
type GrantedProjectView struct {
ProjectID string `json:"-" gorm:"column:project_id;primary_key"`
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
type ProjectGrantView struct {
GrantID string `json:"-" gorm:"column:grant_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id"`
OrgID string `json:"-" gorm:"column:org_id"`
Name string `json:"name" gorm:"column:project_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:project_state"`
Type int32 `json:"-" gorm:"column:project_type"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
OrgName string `json:"-" gorm:"column:org_name"`
OrgDomain string `json:"-" gorm:"column:org_domain"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
GrantID string `json:"-" gorm:"column:grant_id"`
GrantedRoleKeys pq.StringArray `json:"-" gorm:"column:granted_role_keys"`
}
@@ -41,15 +40,14 @@ type ProjectGrant struct {
RoleKeys []string `json:"roleKeys"`
}
func GrantedProjectFromModel(project *model.GrantedProjectView) *GrantedProjectView {
return &GrantedProjectView{
func ProjectGrantFromModel(project *model.ProjectGrantView) *ProjectGrantView {
return &ProjectGrantView{
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: int32(project.State),
Type: int32(project.Type),
ResourceOwner: project.ResourceOwner,
OrgName: project.OrgName,
GrantID: project.GrantID,
@@ -58,15 +56,14 @@ func GrantedProjectFromModel(project *model.GrantedProjectView) *GrantedProjectV
}
}
func GrantedProjectToModel(project *GrantedProjectView) *model.GrantedProjectView {
return &model.GrantedProjectView{
func ProjectGrantToModel(project *ProjectGrantView) *model.ProjectGrantView {
return &model.ProjectGrantView{
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: model.ProjectState(project.State),
Type: model.ProjectType(project.Type),
ResourceOwner: project.ResourceOwner,
OrgName: project.OrgName,
GrantID: project.GrantID,
@@ -74,34 +71,21 @@ func GrantedProjectToModel(project *GrantedProjectView) *model.GrantedProjectVie
}
}
func GrantedProjectsToModel(projects []*GrantedProjectView) []*model.GrantedProjectView {
result := make([]*model.GrantedProjectView, len(projects))
func ProjectGrantsToModel(projects []*ProjectGrantView) []*model.ProjectGrantView {
result := make([]*model.ProjectGrantView, len(projects))
for i, p := range projects {
result[i] = GrantedProjectToModel(p)
result[i] = ProjectGrantToModel(p)
}
return result
}
func (p *GrantedProjectView) AppendEvent(event *models.Event) (err error) {
func (p *ProjectGrantView) AppendEvent(event *models.Event) (err error) {
p.ChangeDate = event.CreationDate
p.Sequence = event.Sequence
switch event.Type {
case es_model.ProjectAdded:
p.State = int32(model.PROJECTSTATE_ACTIVE)
p.CreationDate = event.CreationDate
p.Type = int32(model.PROJECTTYPE_OWNED)
p.setRootData(event)
err = p.setData(event)
case es_model.ProjectChanged:
err = p.setData(event)
case es_model.ProjectDeactivated:
p.State = int32(model.PROJECTSTATE_INACTIVE)
case es_model.ProjectReactivated:
p.State = int32(model.PROJECTSTATE_ACTIVE)
case es_model.ProjectGrantAdded:
p.State = int32(model.PROJECTSTATE_ACTIVE)
p.CreationDate = event.CreationDate
p.Type = int32(model.PROJECTTYPE_GRANTED)
p.setRootData(event)
err = p.setProjectGrantData(event)
case es_model.ProjectGrantChanged:
@@ -114,13 +98,12 @@ func (p *GrantedProjectView) AppendEvent(event *models.Event) (err error) {
return err
}
func (p *GrantedProjectView) setRootData(event *models.Event) {
func (p *ProjectGrantView) setRootData(event *models.Event) {
p.ProjectID = event.AggregateID
p.OrgID = event.ResourceOwner
p.ResourceOwner = event.ResourceOwner
}
func (p *GrantedProjectView) setData(event *models.Event) error {
func (p *ProjectGrantView) setData(event *models.Event) error {
if err := json.Unmarshal(event.Data, p); err != nil {
logging.Log("EVEN-dlo92").WithError(err).Error("could not unmarshal event data")
return err
@@ -128,7 +111,7 @@ func (p *GrantedProjectView) setData(event *models.Event) error {
return nil
}
func (p *GrantedProjectView) setProjectGrantData(event *models.Event) error {
func (p *ProjectGrantView) setProjectGrantData(event *models.Event) error {
grant := new(ProjectGrant)
err := grant.SetData(event)
if err != nil {

View File

@@ -0,0 +1,67 @@
package model
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/view"
)
type ProjectGrantSearchRequest proj_model.ProjectGrantViewSearchRequest
type ProjectGrantSearchQuery proj_model.ProjectGrantViewSearchQuery
type ProjectGrantSearchKey proj_model.ProjectGrantViewSearchKey
func (req ProjectGrantSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req ProjectGrantSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req ProjectGrantSearchRequest) GetSortingColumn() view.ColumnKey {
if req.SortingColumn == proj_model.GRANTEDPROJECTSEARCHKEY_UNSPECIFIED {
return nil
}
return ProjectGrantSearchKey(req.SortingColumn)
}
func (req ProjectGrantSearchRequest) GetAsc() bool {
return req.Asc
}
func (req ProjectGrantSearchRequest) GetQueries() []view.SearchQuery {
result := make([]view.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = ProjectGrantSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req ProjectGrantSearchQuery) GetKey() view.ColumnKey {
return ProjectGrantSearchKey(req.Key)
}
func (req ProjectGrantSearchQuery) GetMethod() global_model.SearchMethod {
return req.Method
}
func (req ProjectGrantSearchQuery) GetValue() interface{} {
return req.Value
}
func (key ProjectGrantSearchKey) ToColumnName() string {
switch proj_model.ProjectGrantViewSearchKey(key) {
case proj_model.GRANTEDPROJECTSEARCHKEY_NAME:
return ProjectGrantKeyName
case proj_model.GRANTEDPROJECTSEARCHKEY_GRANTID:
return ProjectGrantKeyGrantID
case proj_model.GRANTEDPROJECTSEARCHKEY_ORGID:
return ProjectGrantKeyOrgID
case proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID:
return ProjectGrantKeyProjectID
case proj_model.GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER:
return ProjectGrantKeyResourceOwner
default:
return ""
}
}

View File

@@ -20,79 +20,47 @@ func mockProjectGrantData(grant *es_model.ProjectGrant) []byte {
return data
}
func TestGrantedProjectAppendEvent(t *testing.T) {
func TestProjectGrantAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
project *GrantedProjectView
project *ProjectGrantView
}
tests := []struct {
name string
args args
result *GrantedProjectView
result *ProjectGrantView
}{
{
name: "append added project event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectAdded, ResourceOwner: "OrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectName"})},
project: &GrantedProjectView{},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
{
name: "append change project event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectChanged, ResourceOwner: "OrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectNameChanged"})},
project: &GrantedProjectView{ProjectID: "AggregateID", OrgID: "OrgID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectNameChanged", State: int32(model.PROJECTSTATE_ACTIVE)},
},
{
name: "append project deactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectDeactivated, ResourceOwner: "OrgID"},
project: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_INACTIVE)},
},
{
name: "append project reactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectReactivated, ResourceOwner: "OrgID"},
project: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_INACTIVE)},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
{
name: "append added project grant event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectGrantAdded, ResourceOwner: "OrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "GrantID", GrantedOrgID: "GrantedOrgID", RoleKeys: pq.StringArray{"Role"}})},
project: &GrantedProjectView{},
project: &ProjectGrantView{},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
{
name: "append change project grant event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectGrantChanged, ResourceOwner: "OrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "GrantID", RoleKeys: pq.StringArray{"RoleChanged"}})},
project: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"RoleChanged"}},
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"RoleChanged"}},
},
{
name: "append deactivate project grant event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectGrantDeactivated, ResourceOwner: "OrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "GrantID"})},
project: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_INACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_INACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
{
name: "append reactivate project grant event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectGrantReactivated, ResourceOwner: "OrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "GrantID"})},
project: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_INACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_INACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
result: &GrantedProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "OrgID", OrgID: "GrantedOrgID", State: int32(model.PROJECTSTATE_ACTIVE), GrantedRoleKeys: pq.StringArray{"Role"}},
},
}
for _, tt := range tests {

View File

@@ -0,0 +1,63 @@
package model
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/view"
)
type ProjectSearchRequest proj_model.ProjectViewSearchRequest
type ProjectSearchQuery proj_model.ProjectViewSearchQuery
type ProjectSearchKey proj_model.ProjectViewSearchKey
func (req ProjectSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req ProjectSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req ProjectSearchRequest) GetSortingColumn() view.ColumnKey {
if req.SortingColumn == proj_model.PROJECTSEARCHKEY_UNSPECIFIED {
return nil
}
return ProjectSearchKey(req.SortingColumn)
}
func (req ProjectSearchRequest) GetAsc() bool {
return req.Asc
}
func (req ProjectSearchRequest) GetQueries() []view.SearchQuery {
result := make([]view.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = ProjectSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req ProjectSearchQuery) GetKey() view.ColumnKey {
return ProjectSearchKey(req.Key)
}
func (req ProjectSearchQuery) GetMethod() global_model.SearchMethod {
return req.Method
}
func (req ProjectSearchQuery) GetValue() interface{} {
return req.Value
}
func (key ProjectSearchKey) ToColumnName() string {
switch proj_model.ProjectViewSearchKey(key) {
case proj_model.PROJECTSEARCHKEY_NAME:
return ProjectKeyName
case proj_model.PROJECTSEARCHKEY_PROJECTID:
return ProjectKeyProjectID
case proj_model.PROJECTSEARCHKEY_RESOURCE_OWNER:
return ProjectKeyResourceOwner
default:
return ""
}
}

View File

@@ -0,0 +1,70 @@
package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/project/model"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
"testing"
)
func TestProjectAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
project *ProjectView
}
tests := []struct {
name string
args args
result *ProjectView
}{
{
name: "append added project event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectAdded, ResourceOwner: "OrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectName"})},
project: &ProjectView{},
},
result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
{
name: "append change project event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectChanged, ResourceOwner: "OrgID", Data: mockProjectData(&es_model.Project{Name: "ProjectNameChanged"})},
project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectNameChanged", State: int32(model.PROJECTSTATE_ACTIVE)},
},
{
name: "append project deactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectDeactivated, ResourceOwner: "OrgID"},
project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_INACTIVE)},
},
{
name: "append project reactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.ProjectReactivated, ResourceOwner: "OrgID"},
project: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_INACTIVE)},
},
result: &ProjectView{ProjectID: "AggregateID", ResourceOwner: "OrgID", Name: "ProjectName", State: int32(model.PROJECTSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.project.AppendEvent(tt.args.event)
if tt.args.project.ProjectID != tt.result.ProjectID {
t.Errorf("got wrong result projectID: expected: %v, actual: %v ", tt.result.ProjectID, tt.args.project.ProjectID)
}
if tt.args.project.ResourceOwner != tt.result.ResourceOwner {
t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.project.ResourceOwner)
}
if tt.args.project.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, tt.args.project.Name)
}
if tt.args.project.State != tt.result.State {
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, tt.args.project.State)
}
})
}
}

View File

@@ -0,0 +1,60 @@
package view
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view"
"github.com/jinzhu/gorm"
)
func ProjectGrantByProjectAndOrg(db *gorm.DB, table, projectID, orgID string) (*model.ProjectGrantView, error) {
project := new(model.ProjectGrantView)
projectIDQuery := model.ProjectGrantSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS}
orgIDQuery := model.ProjectGrantSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_ORGID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
query := view.PrepareGetByQuery(table, projectIDQuery, orgIDQuery)
err := query(db, project)
return project, err
}
func ProjectGrantByID(db *gorm.DB, table, grantID string) (*model.ProjectGrantView, error) {
project := new(model.ProjectGrantView)
grantIDQuery := model.ProjectGrantSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_GRANTID, Value: grantID, Method: global_model.SEARCHMETHOD_EQUALS}
query := view.PrepareGetByQuery(table, grantIDQuery)
err := query(db, project)
return project, err
}
func ProjectGrantsByProjectID(db *gorm.DB, table, projectID string) ([]*model.ProjectGrantView, error) {
projects := make([]*model.ProjectGrantView, 0)
queries := []*proj_model.ProjectGrantViewSearchQuery{
&proj_model.ProjectGrantViewSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.ProjectGrantSearchRequest{Queries: queries})
_, err := query(db, &projects)
if err != nil {
return nil, err
}
return projects, nil
}
func SearchProjectGrants(db *gorm.DB, table string, req *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, int, error) {
projects := make([]*model.ProjectGrantView, 0)
query := view.PrepareSearchQuery(table, model.ProjectGrantSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &projects)
if err != nil {
return nil, 0, err
}
return projects, count, nil
}
func PutProjectGrant(db *gorm.DB, table string, project *model.ProjectGrantView) error {
save := view.PrepareSave(table)
return save(db, project)
}
func DeleteProjectGrant(db *gorm.DB, table, grantID string) error {
delete := view.PrepareDeleteByKey(table, model.ProjectSearchKey(proj_model.PROJECTGRANTMEMBERSEARCHKEY_GRANT_ID), grantID)
return delete(db)
}

View File

@@ -0,0 +1,51 @@
package view
import (
global_model "github.com/caos/zitadel/internal/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view"
"github.com/jinzhu/gorm"
)
func ProjectByID(db *gorm.DB, table, projectID string) (*model.ProjectView, error) {
project := new(model.ProjectView)
projectIDQuery := model.ProjectSearchQuery{Key: proj_model.PROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS}
query := view.PrepareGetByQuery(table, projectIDQuery)
err := query(db, project)
return project, err
}
func ProjectsByResourceOwner(db *gorm.DB, table, orgID string) ([]*model.ProjectView, error) {
projects := make([]*model.ProjectView, 0)
queries := []*proj_model.ProjectViewSearchQuery{
&proj_model.ProjectViewSearchQuery{Key: proj_model.PROJECTSEARCHKEY_RESOURCE_OWNER, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.ProjectSearchRequest{Queries: queries})
_, err := query(db, &projects)
if err != nil {
return nil, err
}
return projects, nil
}
func SearchProjects(db *gorm.DB, table string, req *proj_model.ProjectViewSearchRequest) ([]*model.ProjectView, int, error) {
projects := make([]*model.ProjectView, 0)
query := view.PrepareSearchQuery(table, model.ProjectSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
count, err := query(db, &projects)
if err != nil {
return nil, 0, err
}
return projects, count, nil
}
func PutProject(db *gorm.DB, table string, project *model.ProjectView) error {
save := view.PrepareSave(table)
return save(db, project)
}
func DeleteProject(db *gorm.DB, table, projectID string) error {
delete := view.PrepareDeleteByKey(table, model.ProjectSearchKey(proj_model.PROJECTSEARCHKEY_PROJECTID), projectID)
return delete(db)
}

View File

@@ -0,0 +1,109 @@
package model
import (
"testing"
)
func TestIsUserValid(t *testing.T) {
type args struct {
user *User
}
tests := []struct {
name string
args args
result bool
errFunc func(err error) bool
}{
{
name: "user with minimal data",
args: args{
user: &User{
Profile: &Profile{
UserName: "UserName",
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
},
},
result: true,
},
{
name: "user with phone data",
args: args{
user: &User{
Profile: &Profile{
UserName: "UserName",
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Phone: &Phone{
PhoneNumber: "+41711234569",
},
},
},
result: true,
},
{
name: "user with address data",
args: args{
user: &User{
Profile: &Profile{
UserName: "UserName",
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Address: &Address{
StreetAddress: "Teufenerstrasse 19",
PostalCode: "9000",
Locality: "St. Gallen",
Country: "Switzerland",
},
},
},
result: true,
},
{
name: "user with all data",
args: args{
user: &User{
Profile: &Profile{
UserName: "UserName",
FirstName: "FirstName",
LastName: "LastName",
},
Email: &Email{
EmailAddress: "Email",
},
Phone: &Phone{
PhoneNumber: "+41711234569",
},
Address: &Address{
StreetAddress: "Teufenerstrasse 19",
PostalCode: "9000",
Locality: "St. Gallen",
Country: "Switzerland",
},
},
},
result: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
isValid := tt.args.user.IsValid()
if tt.result != isValid {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, isValid)
}
})
}
}