mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:27:23 +00:00
fix: project grants (#4031)
* fix: filter granted memberships correctly * fix: only show changes of granted project * Apply suggestions from code review Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com> * Update internal/query/user_membership.go Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com> Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
This commit is contained in:
parent
c15577c1f9
commit
5bd9badbcf
@ -19,6 +19,7 @@ export enum ChangeType {
|
|||||||
USER = 'user',
|
USER = 'user',
|
||||||
ORG = 'org',
|
ORG = 'org',
|
||||||
PROJECT = 'project',
|
PROJECT = 'project',
|
||||||
|
PROJECT_GRANT= 'project-grant',
|
||||||
APP = 'app',
|
APP = 'app',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +94,9 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
case ChangeType.PROJECT:
|
case ChangeType.PROJECT:
|
||||||
first = this.mgmtUserService.listProjectChanges(this.id, 30, 0);
|
first = this.mgmtUserService.listProjectChanges(this.id, 30, 0);
|
||||||
break;
|
break;
|
||||||
|
case ChangeType.PROJECT_GRANT:
|
||||||
|
first = this.mgmtUserService.listProjectGrantChanges(this.id, this.secId, 30, 0);
|
||||||
|
break;
|
||||||
case ChangeType.ORG:
|
case ChangeType.ORG:
|
||||||
first = this.mgmtUserService.listOrgChanges(30, 0);
|
first = this.mgmtUserService.listOrgChanges(30, 0);
|
||||||
break;
|
break;
|
||||||
@ -126,6 +130,9 @@ export class ChangesComponent implements OnInit, OnDestroy {
|
|||||||
case ChangeType.PROJECT:
|
case ChangeType.PROJECT:
|
||||||
more = this.mgmtUserService.listProjectChanges(this.id, 20, cursor);
|
more = this.mgmtUserService.listProjectChanges(this.id, 20, cursor);
|
||||||
break;
|
break;
|
||||||
|
case ChangeType.PROJECT_GRANT:
|
||||||
|
more = this.mgmtUserService.listProjectGrantChanges(this.id, this.secId, 20, cursor);
|
||||||
|
break;
|
||||||
case ChangeType.ORG:
|
case ChangeType.ORG:
|
||||||
more = this.mgmtUserService.listOrgChanges(20, cursor);
|
more = this.mgmtUserService.listOrgChanges(20, cursor);
|
||||||
break;
|
break;
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<div metainfo>
|
<div metainfo>
|
||||||
<cnsl-changes *ngIf="project" [changeType]="ChangeType.PROJECT" [id]="project.projectId"></cnsl-changes>
|
<cnsl-changes *ngIf="project" [changeType]="ChangeType.PROJECT_GRANT" [id]="project.projectId" [secId]="project.grantId"></cnsl-changes>
|
||||||
</div>
|
</div>
|
||||||
</cnsl-meta-layout>
|
</cnsl-meta-layout>
|
||||||
</div>
|
</div>
|
||||||
|
@ -221,6 +221,8 @@ import {
|
|||||||
ListPersonalAccessTokensResponse,
|
ListPersonalAccessTokensResponse,
|
||||||
ListProjectChangesRequest,
|
ListProjectChangesRequest,
|
||||||
ListProjectChangesResponse,
|
ListProjectChangesResponse,
|
||||||
|
ListProjectGrantChangesRequest,
|
||||||
|
ListProjectGrantChangesResponse,
|
||||||
ListProjectGrantMemberRolesRequest,
|
ListProjectGrantMemberRolesRequest,
|
||||||
ListProjectGrantMemberRolesResponse,
|
ListProjectGrantMemberRolesResponse,
|
||||||
ListProjectGrantMembersRequest,
|
ListProjectGrantMembersRequest,
|
||||||
@ -1776,6 +1778,28 @@ export class ManagementService {
|
|||||||
return this.grpcService.mgmt.listProjectChanges(req, null).then((resp) => resp.toObject());
|
return this.grpcService.mgmt.listProjectChanges(req, null).then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public listProjectGrantChanges(
|
||||||
|
projectId: string,
|
||||||
|
grantId: string,
|
||||||
|
limit: number,
|
||||||
|
sequence: number,
|
||||||
|
): Promise<ListProjectGrantChangesResponse.AsObject> {
|
||||||
|
const req = new ListProjectGrantChangesRequest();
|
||||||
|
req.setProjectId(projectId);
|
||||||
|
req.setGrantId(grantId);
|
||||||
|
const query = new ChangeQuery();
|
||||||
|
|
||||||
|
if (limit) {
|
||||||
|
query.setLimit(limit);
|
||||||
|
}
|
||||||
|
if (sequence) {
|
||||||
|
query.setSequence(sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
req.setQuery(query);
|
||||||
|
return this.grpcService.mgmt.listProjectGrantChanges(req, null).then((resp) => resp.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
public listUserChanges(userId: string, limit: number, sequence: number): Promise<ListUserChangesResponse.AsObject> {
|
public listUserChanges(userId: string, limit: number, sequence: number): Promise<ListUserChangesResponse.AsObject> {
|
||||||
const req = new ListUserChangesRequest();
|
const req = new ListUserChangesRequest();
|
||||||
req.setUserId(userId);
|
req.setUserId(userId);
|
||||||
|
@ -1417,6 +1417,19 @@ Removes an app key
|
|||||||
DELETE: /projects/{project_id}/apps/{app_id}/keys/{key_id}
|
DELETE: /projects/{project_id}/apps/{app_id}/keys/{key_id}
|
||||||
|
|
||||||
|
|
||||||
|
### ListProjectGrantChanges
|
||||||
|
|
||||||
|
> **rpc** ListProjectGrantChanges([ListProjectGrantChangesRequest](#listprojectgrantchangesrequest))
|
||||||
|
[ListProjectGrantChangesResponse](#listprojectgrantchangesresponse)
|
||||||
|
|
||||||
|
Returns the history of the project grant (each event)
|
||||||
|
Limit should always be set, there is a default limit set by the service
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POST: /projects/{project_id}/grants/{grant_id}/changes/_search
|
||||||
|
|
||||||
|
|
||||||
### GetProjectGrantByID
|
### GetProjectGrantByID
|
||||||
|
|
||||||
> **rpc** GetProjectGrantByID([GetProjectGrantByIDRequest](#getprojectgrantbyidrequest))
|
> **rpc** GetProjectGrantByID([GetProjectGrantByIDRequest](#getprojectgrantbyidrequest))
|
||||||
@ -5743,6 +5756,30 @@ This is an empty request
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### ListProjectGrantChangesRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Description | Validation |
|
||||||
|
| ----- | ---- | ----------- | ----------- |
|
||||||
|
| query | zitadel.change.v1.ChangeQuery | list limitations and ordering | |
|
||||||
|
| project_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
|
| grant_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### ListProjectGrantChangesResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Description | Validation |
|
||||||
|
| ----- | ---- | ----------- | ----------- |
|
||||||
|
| result | repeated zitadel.change.v1.Change | zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos) | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### ListProjectGrantMemberRolesRequest
|
### ListProjectGrantMemberRolesRequest
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,8 +177,12 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje
|
|||||||
|
|
||||||
if !isIAMAdmin(memberships.Memberships) {
|
if !isIAMAdmin(memberships.Memberships) {
|
||||||
ids := make([]string, 0, len(memberships.Memberships))
|
ids := make([]string, 0, len(memberships.Memberships))
|
||||||
for _, grant := range memberships.Memberships {
|
for _, membership := range memberships.Memberships {
|
||||||
ids = appendIfNotExists(ids, grant.ResourceOwner)
|
orgID := membership.ResourceOwner
|
||||||
|
if membership.ProjectGrant != nil && membership.ProjectGrant.GrantedOrgID != "" {
|
||||||
|
orgID = membership.ProjectGrant.GrantedOrgID
|
||||||
|
}
|
||||||
|
ids = appendIfNotExists(ids, orgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
idsQuery, err := query.NewOrgIDsSearchQuery(ids...)
|
idsQuery, err := query.NewOrgIDsSearchQuery(ids...)
|
||||||
|
@ -55,6 +55,17 @@ func (s *Server) ListProjects(ctx context.Context, req *mgmt_pb.ListProjectsRequ
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListProjectGrantChanges(ctx context.Context, req *mgmt_pb.ListProjectGrantChangesRequest) (*mgmt_pb.ListProjectGrantChangesResponse, error) {
|
||||||
|
sequence, limit, asc := change_grpc.ChangeQueryToQuery(req.Query)
|
||||||
|
res, err := s.query.ProjectGrantChanges(ctx, req.ProjectId, req.GrantId, sequence, limit, asc, s.auditLogRetention)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mgmt_pb.ListProjectGrantChangesResponse{
|
||||||
|
Result: change_grpc.ChangesToPb(res.Changes, s.assetAPIPrefix(ctx)),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) ListGrantedProjects(ctx context.Context, req *mgmt_pb.ListGrantedProjectsRequest) (*mgmt_pb.ListGrantedProjectsResponse, error) {
|
func (s *Server) ListGrantedProjects(ctx context.Context, req *mgmt_pb.ListGrantedProjectsRequest) (*mgmt_pb.ListGrantedProjectsResponse, error) {
|
||||||
queries, err := listGrantedProjectsRequestToModel(req)
|
queries, err := listGrantedProjectsRequestToModel(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,8 +34,12 @@ func (repo *UserMembershipRepo) searchUserMemberships(ctx context.Context) (_ []
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
grantedIDQuery, err := query.NewMembershipGrantedOrgIDSearchQuery(ctxData.OrgID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
memberships, err := repo.Queries.Memberships(ctx, &query.MembershipSearchQuery{
|
memberships, err := repo.Queries.Memberships(ctx, &query.MembershipSearchQuery{
|
||||||
Queries: []query.SearchQuery{userIDQuery, orgIDsQuery},
|
Queries: []query.SearchQuery{userIDQuery, query.Or(orgIDsQuery, grantedIDQuery)},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -50,6 +50,17 @@ func (q *Queries) ProjectChanges(ctx context.Context, projectID string, lastSequ
|
|||||||
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
|
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ProjectGrantChanges(ctx context.Context, projectID, grantID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
|
||||||
|
query := func(query *eventstore.SearchQuery) {
|
||||||
|
query.AggregateTypes(project.AggregateType).
|
||||||
|
AggregateIDs(projectID).
|
||||||
|
EventData(map[string]interface{}{
|
||||||
|
"grantId": grantID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return q.changes(ctx, query, lastSequence, limit, sortAscending, auditLogRetention)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *Queries) ApplicationChanges(ctx context.Context, projectID, appID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
|
func (q *Queries) ApplicationChanges(ctx context.Context, projectID, appID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
|
||||||
query := func(query *eventstore.SearchQuery) {
|
query := func(query *eventstore.SearchQuery) {
|
||||||
query.AggregateTypes(project.AggregateType).
|
query.AggregateTypes(project.AggregateType).
|
||||||
|
@ -312,6 +312,28 @@ func ListComparisonFromMethod(m domain.SearchMethod) ListComparison {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type or struct {
|
||||||
|
queries []SearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
func Or(queries ...SearchQuery) *or {
|
||||||
|
return &or{
|
||||||
|
queries: queries,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *or) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
|
return query.Where(q.comp())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *or) comp() sq.Sqlizer {
|
||||||
|
queries := make([]sq.Sqlizer, 0)
|
||||||
|
for _, query := range q.queries {
|
||||||
|
queries = append(queries, query.comp())
|
||||||
|
}
|
||||||
|
return sq.Or(queries)
|
||||||
|
}
|
||||||
|
|
||||||
type BoolQuery struct {
|
type BoolQuery struct {
|
||||||
Column Column
|
Column Column
|
||||||
Value bool
|
Value bool
|
||||||
|
@ -48,9 +48,10 @@ type ProjectMembership struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProjectGrantMembership struct {
|
type ProjectGrantMembership struct {
|
||||||
ProjectID string
|
ProjectID string
|
||||||
ProjectName string
|
ProjectName string
|
||||||
GrantID string
|
GrantID string
|
||||||
|
GrantedOrgID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MembershipSearchQuery struct {
|
type MembershipSearchQuery struct {
|
||||||
@ -78,6 +79,10 @@ func NewMembershipResourceOwnersSearchQuery(ids ...string) (SearchQuery, error)
|
|||||||
return NewListQuery(membershipResourceOwner, list, ListIn)
|
return NewListQuery(membershipResourceOwner, list, ListIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewMembershipGrantedOrgIDSearchQuery(id string) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(ProjectGrantColumnGrantedOrgID, id, TextEquals)
|
||||||
|
}
|
||||||
|
|
||||||
func NewMembershipProjectIDQuery(value string) (SearchQuery, error) {
|
func NewMembershipProjectIDQuery(value string) (SearchQuery, error) {
|
||||||
return NewTextQuery(membershipProjectID, value, TextEquals)
|
return NewTextQuery(membershipProjectID, value, TextEquals)
|
||||||
}
|
}
|
||||||
@ -173,6 +178,10 @@ var (
|
|||||||
name: projection.ProjectGrantMemberGrantIDCol,
|
name: projection.ProjectGrantMemberGrantIDCol,
|
||||||
table: membershipAlias,
|
table: membershipAlias,
|
||||||
}
|
}
|
||||||
|
membershipGrantGrantedOrgID = Column{
|
||||||
|
name: projection.ProjectGrantColumnGrantedOrgID,
|
||||||
|
table: membershipAlias,
|
||||||
|
}
|
||||||
|
|
||||||
membershipFrom = "(" +
|
membershipFrom = "(" +
|
||||||
prepareOrgMember() +
|
prepareOrgMember() +
|
||||||
@ -197,12 +206,14 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships,
|
|||||||
membershipIAMID.identifier(),
|
membershipIAMID.identifier(),
|
||||||
membershipProjectID.identifier(),
|
membershipProjectID.identifier(),
|
||||||
membershipGrantID.identifier(),
|
membershipGrantID.identifier(),
|
||||||
|
ProjectGrantColumnGrantedOrgID.identifier(),
|
||||||
ProjectColumnName.identifier(),
|
ProjectColumnName.identifier(),
|
||||||
OrgColumnName.identifier(),
|
OrgColumnName.identifier(),
|
||||||
countColumn.identifier(),
|
countColumn.identifier(),
|
||||||
).From(membershipFrom).
|
).From(membershipFrom).
|
||||||
LeftJoin(join(ProjectColumnID, membershipProjectID)).
|
LeftJoin(join(ProjectColumnID, membershipProjectID)).
|
||||||
LeftJoin(join(OrgColumnID, membershipOrgID)).
|
LeftJoin(join(OrgColumnID, membershipOrgID)).
|
||||||
|
LeftJoin(join(ProjectGrantColumnGrantID, membershipGrantID)).
|
||||||
PlaceholderFormat(sq.Dollar),
|
PlaceholderFormat(sq.Dollar),
|
||||||
func(rows *sql.Rows) (*Memberships, error) {
|
func(rows *sql.Rows) (*Memberships, error) {
|
||||||
memberships := make([]*Membership, 0)
|
memberships := make([]*Membership, 0)
|
||||||
@ -210,14 +221,15 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships,
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
membership = new(Membership)
|
membership = new(Membership)
|
||||||
orgID = sql.NullString{}
|
orgID = sql.NullString{}
|
||||||
iamID = sql.NullString{}
|
iamID = sql.NullString{}
|
||||||
projectID = sql.NullString{}
|
projectID = sql.NullString{}
|
||||||
grantID = sql.NullString{}
|
grantID = sql.NullString{}
|
||||||
roles = pq.StringArray{}
|
grantedOrgID = sql.NullString{}
|
||||||
projectName = sql.NullString{}
|
roles = pq.StringArray{}
|
||||||
orgName = sql.NullString{}
|
projectName = sql.NullString{}
|
||||||
|
orgName = sql.NullString{}
|
||||||
)
|
)
|
||||||
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
@ -231,6 +243,7 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships,
|
|||||||
&iamID,
|
&iamID,
|
||||||
&projectID,
|
&projectID,
|
||||||
&grantID,
|
&grantID,
|
||||||
|
&grantedOrgID,
|
||||||
&projectName,
|
&projectName,
|
||||||
&orgName,
|
&orgName,
|
||||||
&count,
|
&count,
|
||||||
@ -252,11 +265,12 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships,
|
|||||||
IAMID: iamID.String,
|
IAMID: iamID.String,
|
||||||
Name: iamID.String,
|
Name: iamID.String,
|
||||||
}
|
}
|
||||||
} else if projectID.Valid && grantID.Valid {
|
} else if projectID.Valid && grantID.Valid && grantedOrgID.Valid {
|
||||||
membership.ProjectGrant = &ProjectGrantMembership{
|
membership.ProjectGrant = &ProjectGrantMembership{
|
||||||
ProjectID: projectID.String,
|
ProjectID: projectID.String,
|
||||||
ProjectName: projectName.String,
|
ProjectName: projectName.String,
|
||||||
GrantID: grantID.String,
|
GrantID: grantID.String,
|
||||||
|
GrantedOrgID: grantedOrgID.String,
|
||||||
}
|
}
|
||||||
} else if projectID.Valid {
|
} else if projectID.Valid {
|
||||||
membership.Project = &ProjectMembership{
|
membership.Project = &ProjectMembership{
|
||||||
@ -346,7 +360,8 @@ func prepareProjectGrantMember() string {
|
|||||||
"NULL::STRING AS "+membershipIAMID.name,
|
"NULL::STRING AS "+membershipIAMID.name,
|
||||||
ProjectGrantMemberProjectID.identifier(),
|
ProjectGrantMemberProjectID.identifier(),
|
||||||
ProjectGrantMemberGrantID.identifier(),
|
ProjectGrantMemberGrantID.identifier(),
|
||||||
).From(projectGrantMemberTable.identifier()).MustSql()
|
).From(projectGrantMemberTable.identifier()).
|
||||||
|
MustSql()
|
||||||
|
|
||||||
return stmt
|
return stmt
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ var (
|
|||||||
", memberships.id" +
|
", memberships.id" +
|
||||||
", memberships.project_id" +
|
", memberships.project_id" +
|
||||||
", memberships.grant_id" +
|
", memberships.grant_id" +
|
||||||
|
", projections.project_grants.granted_org_id" +
|
||||||
", projections.projects.name" +
|
", projections.projects.name" +
|
||||||
", projections.orgs.name" +
|
", projections.orgs.name" +
|
||||||
", COUNT(*) OVER ()" +
|
", COUNT(*) OVER ()" +
|
||||||
@ -80,7 +81,8 @@ var (
|
|||||||
" FROM projections.project_grant_members as members" +
|
" FROM projections.project_grant_members as members" +
|
||||||
") AS memberships" +
|
") AS memberships" +
|
||||||
" LEFT JOIN projections.projects ON memberships.project_id = projections.projects.id" +
|
" LEFT JOIN projections.projects ON memberships.project_id = projections.projects.id" +
|
||||||
" LEFT JOIN projections.orgs ON memberships.org_id = projections.orgs.id")
|
" LEFT JOIN projections.orgs ON memberships.org_id = projections.orgs.id" +
|
||||||
|
" LEFT JOIN projections.project_grants ON memberships.grant_id = projections.project_grants.grant_id")
|
||||||
membershipCols = []string{
|
membershipCols = []string{
|
||||||
"user_id",
|
"user_id",
|
||||||
"roles",
|
"roles",
|
||||||
@ -92,6 +94,7 @@ var (
|
|||||||
"instance_id",
|
"instance_id",
|
||||||
"project_id",
|
"project_id",
|
||||||
"grant_id",
|
"grant_id",
|
||||||
|
"granted_org_id",
|
||||||
"name", //project name
|
"name", //project name
|
||||||
"name", //org name
|
"name", //org name
|
||||||
"count",
|
"count",
|
||||||
@ -141,6 +144,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
"org-name",
|
"org-name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -184,6 +188,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -224,6 +229,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
"project-id",
|
"project-id",
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
"project-name",
|
"project-name",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -266,6 +272,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
"project-id",
|
"project-id",
|
||||||
"grant-id",
|
"grant-id",
|
||||||
|
"granted-org-id",
|
||||||
"project-name",
|
"project-name",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -285,9 +292,10 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
Sequence: 20211202,
|
Sequence: 20211202,
|
||||||
ResourceOwner: "ro",
|
ResourceOwner: "ro",
|
||||||
ProjectGrant: &ProjectGrantMembership{
|
ProjectGrant: &ProjectGrantMembership{
|
||||||
GrantID: "grant-id",
|
GrantID: "grant-id",
|
||||||
ProjectID: "project-id",
|
ProjectID: "project-id",
|
||||||
ProjectName: "project-name",
|
ProjectName: "project-name",
|
||||||
|
GrantedOrgID: "granted-org-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -313,6 +321,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
"org-name",
|
"org-name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -328,6 +337,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user-id",
|
"user-id",
|
||||||
@ -340,6 +350,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
"project-id",
|
"project-id",
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
"project-name",
|
"project-name",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -354,6 +365,7 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
"project-id",
|
"project-id",
|
||||||
"grant-id",
|
"grant-id",
|
||||||
|
"granted-org-id",
|
||||||
"project-name",
|
"project-name",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
@ -400,9 +412,10 @@ func Test_MembershipPrepares(t *testing.T) {
|
|||||||
Sequence: 20211202,
|
Sequence: 20211202,
|
||||||
ResourceOwner: "ro",
|
ResourceOwner: "ro",
|
||||||
ProjectGrant: &ProjectGrantMembership{
|
ProjectGrant: &ProjectGrantMembership{
|
||||||
ProjectID: "project-id",
|
ProjectID: "project-id",
|
||||||
GrantID: "grant-id",
|
GrantID: "grant-id",
|
||||||
ProjectName: "project-name",
|
ProjectName: "project-name",
|
||||||
|
GrantedOrgID: "granted-org-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -16,8 +16,12 @@ func (q *Queries) MyZitadelPermissions(ctx context.Context, orgID, userID string
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
grantedOrgIDQuery, err := NewMembershipGrantedOrgIDSearchQuery(orgID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
memberships, err := q.Memberships(ctx, &MembershipSearchQuery{
|
memberships, err := q.Memberships(ctx, &MembershipSearchQuery{
|
||||||
Queries: []SearchQuery{userIDQuery, orgIDsQuery},
|
Queries: []SearchQuery{userIDQuery, Or(orgIDsQuery, grantedOrgIDQuery)},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -2,47 +2,47 @@ package management
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
|
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/change"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *ListUserChangesResponse) Localizers() []middleware.Localizer {
|
func (c *ListUserChangesResponse) Localizers() []middleware.Localizer {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
localizers := make([]middleware.Localizer, len(c.Result))
|
return changesLocalizers(c.Result)
|
||||||
for i, change := range c.Result {
|
|
||||||
localizers[i] = change.EventType
|
|
||||||
}
|
|
||||||
return localizers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ListOrgChangesResponse) Localizers() []middleware.Localizer {
|
func (c *ListOrgChangesResponse) Localizers() []middleware.Localizer {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
localizers := make([]middleware.Localizer, len(c.Result))
|
return changesLocalizers(c.Result)
|
||||||
for i, change := range c.Result {
|
|
||||||
localizers[i] = change.EventType
|
|
||||||
}
|
|
||||||
return localizers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ListProjectChangesResponse) Localizers() []middleware.Localizer {
|
func (c *ListProjectChangesResponse) Localizers() []middleware.Localizer {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
localizers := make([]middleware.Localizer, len(c.Result))
|
return changesLocalizers(c.Result)
|
||||||
for i, change := range c.Result {
|
}
|
||||||
localizers[i] = change.EventType
|
|
||||||
|
func (c *ListProjectGrantChangesResponse) Localizers() []middleware.Localizer {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return localizers
|
return changesLocalizers(c.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ListAppChangesResponse) Localizers() []middleware.Localizer {
|
func (c *ListAppChangesResponse) Localizers() []middleware.Localizer {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
localizers := make([]middleware.Localizer, len(c.Result))
|
return changesLocalizers(c.Result)
|
||||||
for i, change := range c.Result {
|
}
|
||||||
|
|
||||||
|
func changesLocalizers(changes []*change.Change) []middleware.Localizer {
|
||||||
|
localizers := make([]middleware.Localizer, len(changes))
|
||||||
|
for i, change := range changes {
|
||||||
localizers[i] = change.EventType
|
localizers[i] = change.EventType
|
||||||
}
|
}
|
||||||
return localizers
|
return localizers
|
||||||
|
@ -1045,6 +1045,7 @@ service ManagementService {
|
|||||||
|
|
||||||
option (zitadel.v1.auth_option) = {
|
option (zitadel.v1.auth_option) = {
|
||||||
permission: "project.read"
|
permission: "project.read"
|
||||||
|
check_field_name: "ProjectId"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1470,6 +1471,19 @@ service ManagementService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the history of the project grant (each event)
|
||||||
|
// Limit should always be set, there is a default limit set by the service
|
||||||
|
rpc ListProjectGrantChanges(ListProjectGrantChangesRequest) returns (ListProjectGrantChangesResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/projects/{project_id}/grants/{grant_id}/changes/_search"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.v1.auth_option) = {
|
||||||
|
permission: "project.grant.read"
|
||||||
|
check_field_name: "GrantId"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Returns a project grant (ProjectGrant = Grant another organisation for my project)
|
// Returns a project grant (ProjectGrant = Grant another organisation for my project)
|
||||||
rpc GetProjectGrantByID(GetProjectGrantByIDRequest) returns (GetProjectGrantByIDResponse) {
|
rpc GetProjectGrantByID(GetProjectGrantByIDRequest) returns (GetProjectGrantByIDResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
@ -4100,6 +4114,20 @@ message RemoveAppKeyResponse {
|
|||||||
zitadel.v1.ObjectDetails details = 1;
|
zitadel.v1.ObjectDetails details = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListProjectGrantChangesRequest {
|
||||||
|
//list limitations and ordering
|
||||||
|
zitadel.change.v1.ChangeQuery query = 1;
|
||||||
|
string project_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
string grant_id = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListProjectGrantChangesResponse {
|
||||||
|
reserved 1;
|
||||||
|
reserved "details";
|
||||||
|
// zitadel.v1.ListDetails details = 1; was always returned empty (as we cannot get the necessary infos)
|
||||||
|
repeated zitadel.change.v1.Change result = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message GetProjectGrantByIDRequest {
|
message GetProjectGrantByIDRequest {
|
||||||
string project_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string project_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string grant_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string grant_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user