zitadel/internal/query/project_grant_member.go
Fabienne Bühler 07ce3b6905
chore!: Introduce ZITADEL v3 (#9645)
This PR summarizes multiple changes specifically only available with
ZITADEL v3:

- feat: Web Keys management
(https://github.com/zitadel/zitadel/pull/9526)
- fix(cmd): ensure proper working of mirror
(https://github.com/zitadel/zitadel/pull/9509)
- feat(Authz): system user support for permission check v2
(https://github.com/zitadel/zitadel/pull/9640)
- chore(license): change from Apache to AGPL
(https://github.com/zitadel/zitadel/pull/9597)
- feat(console): list v2 sessions
(https://github.com/zitadel/zitadel/pull/9539)
- fix(console): add loginV2 feature flag
(https://github.com/zitadel/zitadel/pull/9682)
- fix(feature flags): allow reading "own" flags
(https://github.com/zitadel/zitadel/pull/9649)
- feat(console): add Actions V2 UI
(https://github.com/zitadel/zitadel/pull/9591)

BREAKING CHANGE
- feat(webkey): migrate to v2beta API
(https://github.com/zitadel/zitadel/pull/9445)
- chore!: remove CockroachDB Support
(https://github.com/zitadel/zitadel/pull/9444)
- feat(actions): migrate to v2beta API
(https://github.com/zitadel/zitadel/pull/9489)

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
Co-authored-by: Ramon <mail@conblem.me>
Co-authored-by: Elio Bischof <elio@zitadel.com>
Co-authored-by: Kenta Yamaguchi <56732734+KEY60228@users.noreply.github.com>
Co-authored-by: Harsha Reddy <harsha.reddy@klaviyo.com>
Co-authored-by: Livio Spring <livio@zitadel.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Iraq <66622793+kkrime@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@zitadel.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Max Peintner <peintnerm@gmail.com>
2025-04-02 16:53:06 +02:00

204 lines
5.7 KiB
Go

package query
import (
"context"
"database/sql"
sq "github.com/Masterminds/squirrel"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/zerrors"
)
var (
projectGrantMemberTable = table{
name: projection.ProjectGrantMemberProjectionTable,
alias: "members",
instanceIDCol: projection.MemberInstanceID,
}
ProjectGrantMemberUserID = Column{
name: projection.MemberUserIDCol,
table: projectGrantMemberTable,
}
ProjectGrantMemberRoles = Column{
name: projection.MemberRolesCol,
table: projectGrantMemberTable,
}
ProjectGrantMemberCreationDate = Column{
name: projection.MemberCreationDate,
table: projectGrantMemberTable,
}
ProjectGrantMemberChangeDate = Column{
name: projection.MemberChangeDate,
table: projectGrantMemberTable,
}
ProjectGrantMemberSequence = Column{
name: projection.MemberSequence,
table: projectGrantMemberTable,
}
ProjectGrantMemberResourceOwner = Column{
name: projection.MemberResourceOwner,
table: projectGrantMemberTable,
}
ProjectGrantMemberUserResourceOwner = Column{
name: projection.MemberUserResourceOwner,
table: projectGrantMemberTable,
}
ProjectGrantMemberInstanceID = Column{
name: projection.MemberInstanceID,
table: projectGrantMemberTable,
}
ProjectGrantMemberProjectID = Column{
name: projection.ProjectGrantMemberProjectIDCol,
table: projectGrantMemberTable,
}
ProjectGrantMemberGrantID = Column{
name: projection.ProjectGrantMemberGrantIDCol,
table: projectGrantMemberTable,
}
)
type ProjectGrantMembersQuery struct {
MembersQuery
ProjectID, GrantID, OrgID string
}
func (q *ProjectGrantMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return q.MembersQuery.
toQuery(query).
Where(sq.And{
sq.Eq{
ProjectGrantMemberProjectID.identifier(): q.ProjectID,
ProjectGrantMemberGrantID.identifier(): q.GrantID,
},
sq.Or{
sq.Eq{ProjectGrantColumnResourceOwner.identifier(): q.OrgID},
sq.Eq{ProjectGrantColumnGrantedOrgID.identifier(): q.OrgID},
},
})
}
func (q *Queries) ProjectGrantMembers(ctx context.Context, queries *ProjectGrantMembersQuery) (members *Members, err error) {
query, scan := prepareProjectGrantMembersQuery()
eq := sq.Eq{ProjectGrantMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
if err != nil {
return nil, zerrors.ThrowInvalidArgument(err, "QUERY-USNwM", "Errors.Query.InvalidRequest")
}
currentSequence, err := q.latestState(ctx, projectGrantMemberTable)
if err != nil {
return nil, err
}
err = q.client.QueryContext(ctx, func(rows *sql.Rows) error {
members, err = scan(rows)
return err
}, stmt, args...)
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-Pdg1I", "Errors.Internal")
}
members.State = currentSequence
return members, err
}
func prepareProjectGrantMembersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Members, error)) {
return sq.Select(
ProjectGrantMemberCreationDate.identifier(),
ProjectGrantMemberChangeDate.identifier(),
ProjectGrantMemberSequence.identifier(),
ProjectGrantMemberResourceOwner.identifier(),
ProjectGrantMemberUserResourceOwner.identifier(),
ProjectGrantMemberUserID.identifier(),
ProjectGrantMemberRoles.identifier(),
LoginNameNameCol.identifier(),
HumanEmailCol.identifier(),
HumanFirstNameCol.identifier(),
HumanLastNameCol.identifier(),
HumanDisplayNameCol.identifier(),
MachineNameCol.identifier(),
HumanAvatarURLCol.identifier(),
UserTypeCol.identifier(),
countColumn.identifier(),
).From(projectGrantMemberTable.identifier()).
LeftJoin(join(HumanUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(MachineUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(UserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(LoginNameUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(ProjectGrantColumnGrantID, ProjectGrantMemberGrantID)).
Where(
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
).PlaceholderFormat(sq.Dollar),
func(rows *sql.Rows) (*Members, error) {
members := make([]*Member, 0)
var count uint64
for rows.Next() {
member := new(Member)
var (
preferredLoginName = sql.NullString{}
email = sql.NullString{}
firstName = sql.NullString{}
lastName = sql.NullString{}
displayName = sql.NullString{}
machineName = sql.NullString{}
avatarURL = sql.NullString{}
userType = sql.NullInt32{}
)
err := rows.Scan(
&member.CreationDate,
&member.ChangeDate,
&member.Sequence,
&member.ResourceOwner,
&member.UserResourceOwner,
&member.UserID,
&member.Roles,
&preferredLoginName,
&email,
&firstName,
&lastName,
&displayName,
&machineName,
&avatarURL,
&userType,
&count,
)
if err != nil {
return nil, err
}
member.PreferredLoginName = preferredLoginName.String
member.Email = email.String
member.FirstName = firstName.String
member.LastName = lastName.String
member.AvatarURL = avatarURL.String
if displayName.Valid {
member.DisplayName = displayName.String
} else {
member.DisplayName = machineName.String
}
member.UserType = domain.UserType(userType.Int32)
members = append(members, member)
}
if err := rows.Close(); err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-EqJFc", "Errors.Query.CloseRows")
}
return &Members{
Members: members,
SearchResponse: SearchResponse{
Count: count,
},
}, nil
}
}