mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-06 02:32:18 +00:00
feat: user memberships (#537)
* feat: add search user memberships * feat: add search user memberships * feat: read user member ship * feat: add usergrant search key * feat: uesrmemberships based on permissions * feat: merge master * fix: correct permissions * fix: update display name on change profile * fix: merge request converations * fix: err handling * Update internal/user/model/user_membership_view.go Co-authored-by: Silvan <silvan.reusser@gmail.com> Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
package eventstore
|
||||
|
||||
const (
|
||||
projectReadPerm = "project.read"
|
||||
orgMemberReadPerm = "org.member.read"
|
||||
projectMemberReadPerm = "project.member.read"
|
||||
projectGrantMemberReadPerm = "project.member.read"
|
||||
)
|
||||
@@ -3,6 +3,8 @@ package eventstore
|
||||
import (
|
||||
"context"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
@@ -96,7 +98,7 @@ func (repo *UserRepo) SearchUsers(ctx context.Context, request *usr_model.UserSe
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
sequence, err := repo.View.GetLatestUserSequence()
|
||||
logging.Log("EVENT-Lcn7d").OnError(err).Warn("could not read latest user sequence")
|
||||
projects, count, err := repo.View.SearchUsers(request)
|
||||
users, count, err := repo.View.SearchUsers(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -104,7 +106,7 @@ func (repo *UserRepo) SearchUsers(ctx context.Context, request *usr_model.UserSe
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: model.UsersToModel(projects),
|
||||
Result: model.UsersToModel(users),
|
||||
}
|
||||
if err == nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
@@ -215,3 +217,71 @@ func (repo *UserRepo) AddressByID(ctx context.Context, userID string) (*usr_mode
|
||||
func (repo *UserRepo) ChangeAddress(ctx context.Context, address *usr_model.Address) (*usr_model.Address, error) {
|
||||
return repo.UserEvents.ChangeAddress(ctx, address)
|
||||
}
|
||||
|
||||
func (repo *UserRepo) SearchUserMemberships(ctx context.Context, request *usr_model.UserMembershipSearchRequest) (*usr_model.UserMembershipSearchResponse, error) {
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
sequence, err := repo.View.GetLatestUserMembershipSequence()
|
||||
logging.Log("EVENT-Dn7sf").OnError(err).Warn("could not read latest user sequence")
|
||||
|
||||
result := handleSearchUserMembershipsPermissions(ctx, request, sequence)
|
||||
if result != nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
memberships, count, err := repo.View.SearchUserMemberships(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = &usr_model.UserMembershipSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: model.UserMembershipsToModel(memberships),
|
||||
}
|
||||
if err == nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func handleSearchUserMembershipsPermissions(ctx context.Context, request *usr_model.UserMembershipSearchRequest, sequence *repository.CurrentSequence) *usr_model.UserMembershipSearchResponse {
|
||||
permissions := authz.GetAllPermissionsFromCtx(ctx)
|
||||
orgPerm := authz.HasGlobalExplicitPermission(permissions, orgMemberReadPerm)
|
||||
projectPerm := authz.HasGlobalExplicitPermission(permissions, projectMemberReadPerm)
|
||||
projectGrantPerm := authz.HasGlobalExplicitPermission(permissions, projectGrantMemberReadPerm)
|
||||
if orgPerm && projectPerm && projectGrantPerm {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !orgPerm {
|
||||
request.Queries = append(request.Queries, &usr_model.UserMembershipSearchQuery{Key: usr_model.UserMembershipSearchKeyMemberType, Method: global_model.SearchMethodNotEquals, Value: usr_model.MemberTypeOrganisation})
|
||||
}
|
||||
|
||||
ids := authz.GetExplicitPermissionCtxIDs(permissions, projectMemberReadPerm)
|
||||
ids = append(ids, authz.GetExplicitPermissionCtxIDs(permissions, projectGrantMemberReadPerm)...)
|
||||
if _, q := request.GetSearchQuery(usr_model.UserMembershipSearchKeyObjectID); q != nil {
|
||||
containsID := false
|
||||
for _, id := range ids {
|
||||
if id == q.Value {
|
||||
containsID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !containsID {
|
||||
result := &usr_model.UserMembershipSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(0),
|
||||
Result: []*usr_model.UserMembershipView{},
|
||||
}
|
||||
if sequence != nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
request.Queries = append(request.Queries, &usr_model.UserMembershipSearchQuery{Key: usr_model.UserMembershipSearchKeyObjectID, Method: global_model.SearchMethodIsOneOf, Value: ids})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
projectReadPerm = "project.read"
|
||||
)
|
||||
|
||||
type UserGrantRepo struct {
|
||||
SearchLimit uint64
|
||||
UserGrantEvents *grant_event.UserGrantEventStore
|
||||
|
||||
@@ -44,6 +44,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
|
||||
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||
&OrgMember{handler: handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount}, userEvents: repos.UserEvents},
|
||||
&OrgDomain{handler: handler{view, bulkLimit, configs.cycleDuration("OrgDomain"), errorCount}},
|
||||
&UserMembership{handler: handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount}, orgEvents: repos.OrgEvents, projectEvents: repos.ProjectEvents},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
|
||||
"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"
|
||||
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
type UserMembership struct {
|
||||
handler
|
||||
orgEvents *org_event.OrgEventstore
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
userMembershipTable = "management.user_memberships"
|
||||
)
|
||||
|
||||
func (m *UserMembership) ViewModel() string {
|
||||
return userMembershipTable
|
||||
}
|
||||
|
||||
func (m *UserMembership) EventQuery() (*models.SearchQuery, error) {
|
||||
sequence, err := m.view.GetLatestUserMembershipSequence()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(org_es_model.OrgAggregate, proj_es_model.ProjectAggregate).
|
||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
||||
}
|
||||
|
||||
func (m *UserMembership) Reduce(event *models.Event) (err error) {
|
||||
switch event.AggregateType {
|
||||
case org_es_model.OrgAggregate:
|
||||
err = m.processOrg(event)
|
||||
case proj_es_model.ProjectAggregate:
|
||||
err = m.processProject(event)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *UserMembership) processOrg(event *models.Event) (err error) {
|
||||
member := new(usr_es_model.UserMembershipView)
|
||||
err = member.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch event.Type {
|
||||
case org_es_model.OrgMemberAdded:
|
||||
err = m.fillOrgDisplayName(member)
|
||||
case org_es_model.OrgMemberChanged:
|
||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = member.AppendEvent(event)
|
||||
case org_es_model.OrgMemberRemoved:
|
||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
|
||||
case org_es_model.OrgChanged:
|
||||
err = m.updateOrgDisplayName(event)
|
||||
default:
|
||||
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutUserMembership(member, event.Sequence)
|
||||
}
|
||||
|
||||
func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipView) (err error) {
|
||||
org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(member.AggregateID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.DisplayName = org.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UserMembership) updateOrgDisplayName(event *models.Event) error {
|
||||
org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memberships, err := m.view.UserMembershipsByAggregateID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, membership := range memberships {
|
||||
membership.DisplayName = org.Name
|
||||
}
|
||||
return m.view.BulkPutUserMemberships(memberships, event.Sequence)
|
||||
}
|
||||
|
||||
func (m *UserMembership) processProject(event *models.Event) (err error) {
|
||||
member := new(usr_es_model.UserMembershipView)
|
||||
err = member.AppendEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch event.Type {
|
||||
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded:
|
||||
err = m.fillProjectDisplayName(member)
|
||||
case proj_es_model.ProjectMemberChanged:
|
||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = member.AppendEvent(event)
|
||||
case proj_es_model.ProjectMemberRemoved:
|
||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence)
|
||||
case proj_es_model.ProjectGrantMemberChanged:
|
||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = member.AppendEvent(event)
|
||||
case proj_es_model.ProjectGrantMemberRemoved:
|
||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
|
||||
case proj_es_model.ProjectChanged:
|
||||
err = m.updateProjectDisplayName(event)
|
||||
default:
|
||||
return m.view.ProcessedUserMembershipSequence(event.Sequence)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.view.PutUserMembership(member, event.Sequence)
|
||||
}
|
||||
|
||||
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
|
||||
project, err := m.projectEvents.ProjectByID(context.Background(), member.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.DisplayName = project.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
|
||||
project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memberships, err := m.view.UserMembershipsByAggregateID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, membership := range memberships {
|
||||
membership.DisplayName = project.Name
|
||||
}
|
||||
return m.view.BulkPutUserMemberships(memberships, event.Sequence)
|
||||
}
|
||||
|
||||
func (m *UserMembership) OnError(event *models.Event, err error) error {
|
||||
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
|
||||
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
|
||||
}
|
||||
@@ -15,7 +15,7 @@ func (v *View) ApplicationByID(appID string) (*model.ApplicationView, error) {
|
||||
return view.ApplicationByID(v.Db, applicationTable, appID)
|
||||
}
|
||||
|
||||
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) {
|
||||
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
|
||||
return view.SearchApplications(v.Db, applicationTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ func (v *View) VerifiedOrgDomain(domain string) (*model.OrgDomainView, error) {
|
||||
return view.VerifiedOrgDomain(v.Db, orgDomainTable, domain)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgDomains(request *org_model.OrgDomainSearchRequest) ([]*model.OrgDomainView, int, error) {
|
||||
func (v *View) SearchOrgDomains(request *org_model.OrgDomainSearchRequest) ([]*model.OrgDomainView, uint64, error) {
|
||||
return view.SearchOrgDomains(v.Db, orgDomainTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (v *View) OrgMemberByIDs(orgID, userID string) (*model.OrgMemberView, error
|
||||
return view.OrgMemberByIDs(v.Db, orgMemberTable, orgID, userID)
|
||||
}
|
||||
|
||||
func (v *View) SearchOrgMembers(request *org_model.OrgMemberSearchRequest) ([]*model.OrgMemberView, int, error) {
|
||||
func (v *View) SearchOrgMembers(request *org_model.OrgMemberSearchRequest) ([]*model.OrgMemberView, uint64, error) {
|
||||
return view.SearchOrgMembers(v.Db, orgMemberTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ 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) {
|
||||
func (v *View) SearchProjects(request *proj_model.ProjectViewSearchRequest) ([]*model.ProjectView, uint64, error) {
|
||||
return view.SearchProjects(v.Db, projectTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ func (v *View) ProjectGrantsByProjectIDAndRoleKey(projectID, key string) ([]*mod
|
||||
return view.ProjectGrantsByProjectIDAndRoleKey(v.Db, grantedProjectTable, projectID, key)
|
||||
}
|
||||
|
||||
func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, int, error) {
|
||||
func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, uint64, error) {
|
||||
return view.SearchProjectGrants(v.Db, grantedProjectTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (v *View) ProjectGrantMemberByIDs(projectID, userID string) (*model.Project
|
||||
return view.ProjectGrantMemberByIDs(v.Db, projectGrantMemberTable, projectID, userID)
|
||||
}
|
||||
|
||||
func (v *View) SearchProjectGrantMembers(request *proj_model.ProjectGrantMemberSearchRequest) ([]*model.ProjectGrantMemberView, int, error) {
|
||||
func (v *View) SearchProjectGrantMembers(request *proj_model.ProjectGrantMemberSearchRequest) ([]*model.ProjectGrantMemberView, uint64, error) {
|
||||
return view.SearchProjectGrantMembers(v.Db, projectGrantMemberTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (v *View) ProjectMemberByIDs(projectID, userID string) (*model.ProjectMembe
|
||||
return view.ProjectMemberByIDs(v.Db, projectMemberTable, projectID, userID)
|
||||
}
|
||||
|
||||
func (v *View) SearchProjectMembers(request *proj_model.ProjectMemberSearchRequest) ([]*model.ProjectMemberView, int, error) {
|
||||
func (v *View) SearchProjectMembers(request *proj_model.ProjectMemberSearchRequest) ([]*model.ProjectMemberView, uint64, error) {
|
||||
return view.SearchProjectMembers(v.Db, projectMemberTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ func (v *View) ResourceOwnerProjectRoles(projectID, resourceowner string) ([]*mo
|
||||
return view.ResourceOwnerProjectRoles(v.Db, projectRoleTable, projectID, resourceowner)
|
||||
}
|
||||
|
||||
func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest) ([]*model.ProjectRoleView, int, error) {
|
||||
func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest) ([]*model.ProjectRoleView, uint64, error) {
|
||||
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (v *View) UserByID(userID string) (*model.UserView, error) {
|
||||
return view.UserByID(v.Db, userTable, userID)
|
||||
}
|
||||
|
||||
func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserView, int, error) {
|
||||
func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserView, uint64, error) {
|
||||
return view.SearchUsers(v.Db, userTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) {
|
||||
return view.UserGrantByID(v.Db, userGrantTable, grantID)
|
||||
}
|
||||
|
||||
func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) {
|
||||
func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, uint64, error) {
|
||||
return view.SearchUserGrants(v.Db, userGrantTable, request)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
userMembershipTable = "management.user_memberships"
|
||||
)
|
||||
|
||||
func (v *View) UserMembershipByIDs(userID, aggregateID, objectID string, memberType usr_model.MemberType) (*model.UserMembershipView, error) {
|
||||
return view.UserMembershipByIDs(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
|
||||
}
|
||||
|
||||
func (v *View) UserMembershipsByAggregateID(aggregateID string) ([]*model.UserMembershipView, error) {
|
||||
return view.UserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
|
||||
}
|
||||
|
||||
func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequest) ([]*model.UserMembershipView, uint64, error) {
|
||||
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
|
||||
}
|
||||
|
||||
func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64) error {
|
||||
err := view.PutUserMembership(v.Db, userMembershipTable, membership)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedUserMembershipSequence(sequence)
|
||||
}
|
||||
|
||||
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
|
||||
err := view.PutUserMemberships(v.Db, userTable, memberships...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return v.ProcessedUserMembershipSequence(sequence)
|
||||
}
|
||||
|
||||
func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64) error {
|
||||
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return v.ProcessedUserMembershipSequence(eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
|
||||
return v.latestSequence(userMembershipTable)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedUserMembershipSequence(eventSequence uint64) error {
|
||||
return v.saveCurrentSequence(userMembershipTable, eventSequence)
|
||||
}
|
||||
|
||||
func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
||||
return v.latestFailedEvent(userMembershipTable, sequence)
|
||||
}
|
||||
|
||||
func (v *View) ProcessedUserMembershipFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||
return v.saveFailedEvent(failedEvent)
|
||||
}
|
||||
@@ -37,4 +37,6 @@ type UserRepository interface {
|
||||
|
||||
AddressByID(ctx context.Context, userID string) (*model.Address, error)
|
||||
ChangeAddress(ctx context.Context, address *model.Address) (*model.Address, error)
|
||||
|
||||
SearchUserMemberships(ctx context.Context, request *model.UserMembershipSearchRequest) (*model.UserMembershipSearchResponse, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user