mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-24 03:36:46 +00:00
…of project grant # Which Problems Are Solved On Management API the fields for `GrantedOrgId`, `GrantedOrgName` and `GrantedOrgDomain` were only filled if it was a usergrant for a granted project. # How the Problems Are Solved Correctly query the Organization of the User again to the Organization the Project is granted to. Then fill in the information about the Organization of the User in the fields `GrantedOrgId`, `GrantedOrgName` and `GrantedOrgDomain`. # Additional Changes Additionally query the information about the Organization the Project is granted to, to have it available for the Authorization v2beta API. # Additional Context Closes #10723 --------- Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
667 lines
20 KiB
Go
667 lines
20 KiB
Go
package query
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"slices"
|
|
"time"
|
|
|
|
sq "github.com/Masterminds/squirrel"
|
|
"github.com/zitadel/logging"
|
|
|
|
"github.com/zitadel/zitadel/internal/api/authz"
|
|
"github.com/zitadel/zitadel/internal/database"
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
|
"github.com/zitadel/zitadel/internal/query/projection"
|
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
type UserGrant struct {
|
|
// ID represents the aggregate id (id of the user grant)
|
|
ID string `json:"id,omitempty"`
|
|
CreationDate time.Time `json:"creation_date,omitempty"`
|
|
ChangeDate time.Time `json:"change_date,omitempty"`
|
|
Sequence uint64 `json:"sequence,omitempty"`
|
|
Roles database.TextArray[string] `json:"roles,omitempty"`
|
|
// GrantID represents the project grant id
|
|
GrantID string `json:"grant_id,omitempty"`
|
|
State domain.UserGrantState `json:"state,omitempty"`
|
|
|
|
UserID string `json:"user_id,omitempty"`
|
|
Username string `json:"username,omitempty"`
|
|
UserType domain.UserType `json:"user_type,omitempty"`
|
|
UserResourceOwner string `json:"user_resource_owner,omitempty"`
|
|
UserResourceOwnerName string `json:"user_resource_owner_name,omitempty"`
|
|
UserResourceOwnerDomain string `json:"user_resource_owner_domain,omitempty"`
|
|
FirstName string `json:"first_name,omitempty"`
|
|
LastName string `json:"last_name,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
DisplayName string `json:"display_name,omitempty"`
|
|
AvatarURL string `json:"avatar_url,omitempty"`
|
|
PreferredLoginName string `json:"preferred_login_name,omitempty"`
|
|
|
|
ResourceOwner string `json:"resource_owner,omitempty"`
|
|
OrgName string `json:"org_name,omitempty"`
|
|
OrgPrimaryDomain string `json:"org_primary_domain,omitempty"`
|
|
|
|
ProjectResourceOwner string `json:"project_resource_owner,omitempty"`
|
|
ProjectID string `json:"project_id,omitempty"`
|
|
ProjectName string `json:"project_name,omitempty"`
|
|
|
|
GrantedOrgID string `json:"granted_org_id,omitempty"`
|
|
GrantedOrgName string `json:"granted_org_name,omitempty"`
|
|
GrantedOrgDomain string `json:"granted_org_domain,omitempty"`
|
|
}
|
|
|
|
type UserGrants struct {
|
|
SearchResponse
|
|
UserGrants []*UserGrant
|
|
}
|
|
|
|
func userGrantsCheckPermission(ctx context.Context, grants *UserGrants, permissionCheck domain.PermissionCheck) {
|
|
grants.UserGrants = slices.DeleteFunc(grants.UserGrants,
|
|
func(grant *UserGrant) bool {
|
|
return userGrantCheckPermission(ctx, grant.ResourceOwner, grant.ProjectID, grant.GrantID, grant.UserID, permissionCheck) != nil
|
|
},
|
|
)
|
|
}
|
|
|
|
func userGrantCheckPermission(ctx context.Context, resourceOwner, projectID, grantID, userID string, permissionCheck domain.PermissionCheck) error {
|
|
// you should always be able to read your own permissions
|
|
if authz.GetCtxData(ctx).UserID == userID {
|
|
return nil
|
|
}
|
|
// check permission on the project grant
|
|
if grantID != "" {
|
|
return permissionCheck(ctx, domain.PermissionUserGrantRead, resourceOwner, grantID)
|
|
}
|
|
// check on project
|
|
return permissionCheck(ctx, domain.PermissionUserGrantRead, resourceOwner, projectID)
|
|
}
|
|
|
|
type UserGrantsQueries struct {
|
|
SearchRequest
|
|
Queries []SearchQuery
|
|
}
|
|
|
|
func (q *UserGrantsQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
|
query = q.SearchRequest.toQuery(query)
|
|
for _, q := range q.Queries {
|
|
query = q.toQuery(query)
|
|
}
|
|
return query
|
|
}
|
|
|
|
func userGrantPermissionCheckV2(ctx context.Context, query sq.SelectBuilder, enabled bool, queries *UserGrantsQueries) sq.SelectBuilder {
|
|
if !enabled {
|
|
return query
|
|
}
|
|
join, args := PermissionClause(
|
|
ctx,
|
|
UserGrantResourceOwner,
|
|
domain.PermissionUserGrantRead,
|
|
SingleOrgPermissionOption(queries.Queries),
|
|
WithProjectsPermissionOption(UserGrantProjectID),
|
|
OwnedRowsPermissionOption(UserGrantUserID),
|
|
)
|
|
return query.JoinClause(join, args...)
|
|
}
|
|
|
|
func NewUserGrantUserIDSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantUserID, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantProjectIDSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantProjectID, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantProjectOwnerSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(ProjectColumnResourceOwner, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantResourceOwnerSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantResourceOwner, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantUserResourceOwnerSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserResourceOwnerCol, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantGrantIDSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantGrantID, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantIDSearchQuery(id string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantID, id, TextEquals)
|
|
}
|
|
|
|
func NewUserGrantInIDsSearchQuery(ids []string) (SearchQuery, error) {
|
|
list := make([]interface{}, len(ids))
|
|
for i, value := range ids {
|
|
list[i] = value
|
|
}
|
|
return NewListQuery(UserGrantID, list, ListIn)
|
|
}
|
|
|
|
func NewUserGrantUserTypeQuery(typ domain.UserType) (SearchQuery, error) {
|
|
return NewNumberQuery(UserTypeCol, typ, NumberEquals)
|
|
}
|
|
|
|
func NewUserGrantDisplayNameQuery(displayName string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(HumanDisplayNameCol, displayName, method)
|
|
}
|
|
|
|
func NewUserGrantEmailQuery(email string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(HumanEmailCol, email, method)
|
|
}
|
|
|
|
func NewUserGrantFirstNameQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(HumanFirstNameCol, value, method)
|
|
}
|
|
|
|
func NewUserGrantLastNameQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(HumanLastNameCol, value, method)
|
|
}
|
|
|
|
func NewUserGrantUsernameQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(UserUsernameCol, value, method)
|
|
}
|
|
|
|
func NewUserGrantDomainQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(OrgColumnDomain, value, method)
|
|
}
|
|
|
|
func NewUserGrantOrgNameQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(OrgColumnName, value, method)
|
|
}
|
|
|
|
func NewUserGrantProjectNameQuery(value string, method TextComparison) (SearchQuery, error) {
|
|
return NewTextQuery(ProjectColumnName, value, method)
|
|
}
|
|
|
|
func NewUserGrantRoleQuery(value string) (SearchQuery, error) {
|
|
return NewTextQuery(UserGrantRoles, value, TextListContains)
|
|
}
|
|
|
|
func NewUserGrantStateQuery(value domain.UserGrantState) (SearchQuery, error) {
|
|
return NewNumberQuery(UserGrantState, value, NumberEquals)
|
|
}
|
|
|
|
func NewUserGrantWithGrantedQuery(owner string) (SearchQuery, error) {
|
|
orgQuery, err := NewUserGrantResourceOwnerSearchQuery(owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
projectQuery, err := NewUserGrantProjectOwnerSearchQuery(owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewOrQuery(orgQuery, projectQuery)
|
|
}
|
|
|
|
func NewUserGrantContainsRolesSearchQuery(roles ...string) (SearchQuery, error) {
|
|
r := make([]interface{}, len(roles))
|
|
for i, role := range roles {
|
|
r[i] = role
|
|
}
|
|
return NewListQuery(UserGrantRoles, r, ListIn)
|
|
}
|
|
|
|
var (
|
|
userGrantTable = table{
|
|
name: projection.UserGrantProjectionTable,
|
|
instanceIDCol: projection.UserGrantInstanceID,
|
|
}
|
|
UserGrantID = Column{
|
|
name: projection.UserGrantID,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantResourceOwner = Column{
|
|
name: projection.UserGrantResourceOwner,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantInstanceID = Column{
|
|
name: projection.UserGrantInstanceID,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantCreationDate = Column{
|
|
name: projection.UserGrantCreationDate,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantChangeDate = Column{
|
|
name: projection.UserGrantChangeDate,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantSequence = Column{
|
|
name: projection.UserGrantSequence,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantUserID = Column{
|
|
name: projection.UserGrantUserID,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantProjectID = Column{
|
|
name: projection.UserGrantProjectID,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantGrantID = Column{
|
|
name: projection.UserGrantGrantID,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantRoles = Column{
|
|
name: projection.UserGrantRoles,
|
|
table: userGrantTable,
|
|
}
|
|
UserGrantState = Column{
|
|
name: projection.UserGrantState,
|
|
table: userGrantTable,
|
|
}
|
|
|
|
UserOrgsTable = table{
|
|
name: projection.OrgProjectionTable,
|
|
alias: "user_orgs",
|
|
instanceIDCol: projection.OrgColumnInstanceID,
|
|
}
|
|
UserOrgColumnId = Column{
|
|
name: projection.OrgColumnID,
|
|
table: UserOrgsTable,
|
|
}
|
|
UserOrgColumnName = Column{
|
|
name: projection.OrgColumnName,
|
|
table: UserOrgsTable,
|
|
}
|
|
UserOrgColumnDomain = Column{
|
|
name: projection.OrgColumnDomain,
|
|
table: UserOrgsTable,
|
|
}
|
|
|
|
GrantedOrgsTable = table{
|
|
name: projection.OrgProjectionTable,
|
|
alias: "granted_orgs",
|
|
instanceIDCol: projection.OrgColumnInstanceID,
|
|
}
|
|
GrantedOrgColumnId = Column{
|
|
name: projection.OrgColumnID,
|
|
table: GrantedOrgsTable,
|
|
}
|
|
GrantedOrgColumnName = Column{
|
|
name: projection.OrgColumnName,
|
|
table: GrantedOrgsTable,
|
|
}
|
|
GrantedOrgColumnDomain = Column{
|
|
name: projection.OrgColumnDomain,
|
|
table: GrantedOrgsTable,
|
|
}
|
|
)
|
|
|
|
func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, queries ...SearchQuery) (grant *UserGrant, err error) {
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
if shouldTriggerBulk {
|
|
_, traceSpan := tracing.NewNamedSpan(ctx, "TriggerUserGrantProjection")
|
|
ctx, err = projection.UserGrantProjection.Trigger(ctx, handler.WithAwaitRunning())
|
|
logging.OnError(err).Debug("trigger failed")
|
|
traceSpan.EndWithError(err)
|
|
}
|
|
|
|
query, scan := prepareUserGrantQuery()
|
|
for _, q := range queries {
|
|
query = q.toQuery(query)
|
|
}
|
|
eq := sq.Eq{UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
|
stmt, args, err := query.Where(eq).ToSql()
|
|
if err != nil {
|
|
return nil, zerrors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement")
|
|
}
|
|
|
|
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
|
grant, err = scan(row)
|
|
return err
|
|
}, stmt, args...)
|
|
return grant, err
|
|
}
|
|
|
|
func (q *Queries) UserGrants(ctx context.Context, queries *UserGrantsQueries, shouldTriggerBulk bool, permissionCheck domain.PermissionCheck) (*UserGrants, error) {
|
|
// removed as permission v2 is not implemented yet for project grant level permissions
|
|
// permissionCheckV2 := PermissionV2(ctx, permissionCheck)
|
|
grants, err := q.userGrants(ctx, queries, shouldTriggerBulk, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if permissionCheck != nil { // && !authz.GetFeatures(ctx).PermissionCheckV2 {
|
|
userGrantsCheckPermission(ctx, grants, permissionCheck)
|
|
}
|
|
return grants, nil
|
|
}
|
|
|
|
func (q *Queries) userGrants(ctx context.Context, queries *UserGrantsQueries, shouldTriggerBulk bool, permissionCheckV2 bool) (grants *UserGrants, err error) {
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
if shouldTriggerBulk {
|
|
_, traceSpan := tracing.NewNamedSpan(ctx, "TriggerUserGrantProjection")
|
|
ctx, err = projection.UserGrantProjection.Trigger(ctx, handler.WithAwaitRunning())
|
|
logging.OnError(err).Debug("unable to trigger")
|
|
traceSpan.EndWithError(err)
|
|
}
|
|
|
|
query, scan := prepareUserGrantsQuery()
|
|
query = userGrantPermissionCheckV2(ctx, query, permissionCheckV2, queries)
|
|
eq := sq.Eq{UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
|
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
|
if err != nil {
|
|
return nil, zerrors.ThrowInternal(err, "QUERY-wXnQR", "Errors.Query.SQLStatement")
|
|
}
|
|
|
|
latestState, err := q.latestState(ctx, userGrantTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = q.client.QueryContext(ctx, func(rows *sql.Rows) error {
|
|
grants, err = scan(rows)
|
|
return err
|
|
}, stmt, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
grants.State = latestState
|
|
return grants, nil
|
|
}
|
|
|
|
func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, error)) {
|
|
return sq.Select(
|
|
UserGrantID.identifier(),
|
|
UserGrantCreationDate.identifier(),
|
|
UserGrantChangeDate.identifier(),
|
|
UserGrantSequence.identifier(),
|
|
UserGrantGrantID.identifier(),
|
|
UserGrantRoles.identifier(),
|
|
UserGrantState.identifier(),
|
|
|
|
UserGrantUserID.identifier(),
|
|
UserUsernameCol.identifier(),
|
|
UserTypeCol.identifier(),
|
|
UserOrgColumnId.identifier(),
|
|
UserOrgColumnName.identifier(),
|
|
UserOrgColumnDomain.identifier(),
|
|
HumanFirstNameCol.identifier(),
|
|
HumanLastNameCol.identifier(),
|
|
HumanEmailCol.identifier(),
|
|
HumanDisplayNameCol.identifier(),
|
|
HumanAvatarURLCol.identifier(),
|
|
LoginNameNameCol.identifier(),
|
|
|
|
UserGrantResourceOwner.identifier(),
|
|
OrgColumnName.identifier(),
|
|
OrgColumnDomain.identifier(),
|
|
|
|
UserGrantProjectID.identifier(),
|
|
ProjectColumnName.identifier(),
|
|
ProjectColumnResourceOwner.identifier(),
|
|
|
|
GrantedOrgColumnId.identifier(),
|
|
GrantedOrgColumnName.identifier(),
|
|
GrantedOrgColumnDomain.identifier(),
|
|
).
|
|
From(userGrantTable.identifier()).
|
|
LeftJoin(join(UserIDCol, UserGrantUserID)).
|
|
LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
|
|
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
|
|
LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
|
|
LeftJoin(join(UserOrgColumnId, UserResourceOwnerCol)).
|
|
LeftJoin(join(ProjectGrantColumnGrantID, UserGrantGrantID) + " AND " + ProjectGrantColumnProjectID.identifier() + " = " + UserGrantProjectID.identifier()).
|
|
LeftJoin(join(GrantedOrgColumnId, ProjectGrantColumnGrantedOrgID)).
|
|
LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
|
|
Where(
|
|
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
|
|
).PlaceholderFormat(sq.Dollar),
|
|
func(row *sql.Row) (*UserGrant, error) {
|
|
g := new(UserGrant)
|
|
|
|
var (
|
|
username sql.NullString
|
|
firstName sql.NullString
|
|
userType sql.NullInt32
|
|
userOwner sql.NullString
|
|
userOwnerName sql.NullString
|
|
userOwnerDomain sql.NullString
|
|
lastName sql.NullString
|
|
email sql.NullString
|
|
displayName sql.NullString
|
|
avatarURL sql.NullString
|
|
preferredLoginName sql.NullString
|
|
|
|
orgName sql.NullString
|
|
orgDomain sql.NullString
|
|
|
|
projectName sql.NullString
|
|
projectResourceOwner sql.NullString
|
|
|
|
grantedOrgID sql.NullString
|
|
grantedOrgName sql.NullString
|
|
grantedOrgDomain sql.NullString
|
|
)
|
|
|
|
err := row.Scan(
|
|
&g.ID,
|
|
&g.CreationDate,
|
|
&g.ChangeDate,
|
|
&g.Sequence,
|
|
&g.GrantID,
|
|
&g.Roles,
|
|
&g.State,
|
|
|
|
&g.UserID,
|
|
&username,
|
|
&userType,
|
|
&userOwner,
|
|
&userOwnerName,
|
|
&userOwnerDomain,
|
|
&firstName,
|
|
&lastName,
|
|
&email,
|
|
&displayName,
|
|
&avatarURL,
|
|
&preferredLoginName,
|
|
|
|
&g.ResourceOwner,
|
|
&orgName,
|
|
&orgDomain,
|
|
|
|
&g.ProjectID,
|
|
&projectName,
|
|
&projectResourceOwner,
|
|
|
|
&grantedOrgID,
|
|
&grantedOrgName,
|
|
&grantedOrgDomain,
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, zerrors.ThrowNotFound(err, "QUERY-wIPkA", "Errors.UserGrant.NotFound")
|
|
}
|
|
return nil, zerrors.ThrowInternal(err, "QUERY-oQPcP", "Errors.Internal")
|
|
}
|
|
|
|
g.Username = username.String
|
|
g.UserType = domain.UserType(userType.Int32)
|
|
g.UserResourceOwner = userOwner.String
|
|
g.UserResourceOwnerName = userOwnerName.String
|
|
g.UserResourceOwnerDomain = userOwnerDomain.String
|
|
g.FirstName = firstName.String
|
|
g.LastName = lastName.String
|
|
g.Email = email.String
|
|
g.DisplayName = displayName.String
|
|
g.AvatarURL = avatarURL.String
|
|
g.PreferredLoginName = preferredLoginName.String
|
|
g.OrgName = orgName.String
|
|
g.OrgPrimaryDomain = orgDomain.String
|
|
g.ProjectName = projectName.String
|
|
g.ProjectResourceOwner = projectResourceOwner.String
|
|
g.GrantedOrgID = grantedOrgID.String
|
|
g.GrantedOrgName = grantedOrgName.String
|
|
g.GrantedOrgDomain = grantedOrgDomain.String
|
|
return g, nil
|
|
}
|
|
}
|
|
|
|
func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, error)) {
|
|
return sq.Select(
|
|
UserGrantID.identifier(),
|
|
UserGrantCreationDate.identifier(),
|
|
UserGrantChangeDate.identifier(),
|
|
UserGrantSequence.identifier(),
|
|
UserGrantGrantID.identifier(),
|
|
UserGrantRoles.identifier(),
|
|
UserGrantState.identifier(),
|
|
|
|
UserGrantUserID.identifier(),
|
|
UserUsernameCol.identifier(),
|
|
UserTypeCol.identifier(),
|
|
UserOrgColumnId.identifier(),
|
|
UserOrgColumnName.identifier(),
|
|
UserOrgColumnDomain.identifier(),
|
|
HumanFirstNameCol.identifier(),
|
|
HumanLastNameCol.identifier(),
|
|
HumanEmailCol.identifier(),
|
|
HumanDisplayNameCol.identifier(),
|
|
HumanAvatarURLCol.identifier(),
|
|
LoginNameNameCol.identifier(),
|
|
|
|
UserGrantResourceOwner.identifier(),
|
|
OrgColumnName.identifier(),
|
|
OrgColumnDomain.identifier(),
|
|
|
|
UserGrantProjectID.identifier(),
|
|
ProjectColumnName.identifier(),
|
|
ProjectColumnResourceOwner.identifier(),
|
|
|
|
GrantedOrgColumnId.identifier(),
|
|
GrantedOrgColumnName.identifier(),
|
|
GrantedOrgColumnDomain.identifier(),
|
|
|
|
countColumn.identifier(),
|
|
).
|
|
From(userGrantTable.identifier()).
|
|
LeftJoin(join(UserIDCol, UserGrantUserID)).
|
|
LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
|
|
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
|
|
LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
|
|
LeftJoin(join(UserOrgColumnId, UserResourceOwnerCol)).
|
|
LeftJoin(join(ProjectGrantColumnGrantID, UserGrantGrantID) + " AND " + ProjectGrantColumnProjectID.identifier() + " = " + UserGrantProjectID.identifier()).
|
|
LeftJoin(join(GrantedOrgColumnId, ProjectGrantColumnGrantedOrgID)).
|
|
LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
|
|
Where(
|
|
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
|
|
).PlaceholderFormat(sq.Dollar),
|
|
func(rows *sql.Rows) (*UserGrants, error) {
|
|
userGrants := make([]*UserGrant, 0)
|
|
var count uint64
|
|
for rows.Next() {
|
|
g := new(UserGrant)
|
|
|
|
var (
|
|
username sql.NullString
|
|
userType sql.NullInt32
|
|
userOwner sql.NullString
|
|
userOwnerName sql.NullString
|
|
userOwnerDomain sql.NullString
|
|
firstName sql.NullString
|
|
lastName sql.NullString
|
|
email sql.NullString
|
|
displayName sql.NullString
|
|
avatarURL sql.NullString
|
|
preferredLoginName sql.NullString
|
|
|
|
orgName sql.NullString
|
|
orgDomain sql.NullString
|
|
|
|
grantedOrgID sql.NullString
|
|
grantedOrgName sql.NullString
|
|
grantedOrgDomain sql.NullString
|
|
|
|
projectName sql.NullString
|
|
projectResourceOwner sql.NullString
|
|
)
|
|
|
|
err := rows.Scan(
|
|
&g.ID,
|
|
&g.CreationDate,
|
|
&g.ChangeDate,
|
|
&g.Sequence,
|
|
&g.GrantID,
|
|
&g.Roles,
|
|
&g.State,
|
|
|
|
&g.UserID,
|
|
&username,
|
|
&userType,
|
|
&userOwner,
|
|
&userOwnerName,
|
|
&userOwnerDomain,
|
|
&firstName,
|
|
&lastName,
|
|
&email,
|
|
&displayName,
|
|
&avatarURL,
|
|
&preferredLoginName,
|
|
|
|
&g.ResourceOwner,
|
|
&orgName,
|
|
&orgDomain,
|
|
|
|
&g.ProjectID,
|
|
&projectName,
|
|
&projectResourceOwner,
|
|
|
|
&grantedOrgID,
|
|
&grantedOrgName,
|
|
&grantedOrgDomain,
|
|
|
|
&count,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
g.Username = username.String
|
|
g.UserType = domain.UserType(userType.Int32)
|
|
g.UserResourceOwner = userOwner.String
|
|
g.UserResourceOwnerName = userOwnerName.String
|
|
g.UserResourceOwnerDomain = userOwnerDomain.String
|
|
g.FirstName = firstName.String
|
|
g.LastName = lastName.String
|
|
g.Email = email.String
|
|
g.DisplayName = displayName.String
|
|
g.AvatarURL = avatarURL.String
|
|
g.PreferredLoginName = preferredLoginName.String
|
|
g.OrgName = orgName.String
|
|
g.OrgPrimaryDomain = orgDomain.String
|
|
g.ProjectName = projectName.String
|
|
g.ProjectResourceOwner = projectResourceOwner.String
|
|
g.GrantedOrgID = grantedOrgID.String
|
|
g.GrantedOrgName = grantedOrgName.String
|
|
g.GrantedOrgDomain = grantedOrgDomain.String
|
|
|
|
userGrants = append(userGrants, g)
|
|
}
|
|
|
|
if err := rows.Close(); err != nil {
|
|
return nil, zerrors.ThrowInternal(err, "QUERY-iGvmP", "Errors.Query.CloseRows")
|
|
}
|
|
|
|
return &UserGrants{
|
|
UserGrants: userGrants,
|
|
SearchResponse: SearchResponse{
|
|
Count: count,
|
|
},
|
|
}, nil
|
|
}
|
|
}
|