zitadel/internal/query/user_schema.go
Stefan Benz 41ae35f2ef
feat: add schema user create and remove (#8494)
# Which Problems Are Solved

Added functionality that user with a userschema can be created and
removed.

# How the Problems Are Solved

Added logic and moved APIs so that everything is API v3 conform.

# Additional Changes

- move of user and userschema API to resources folder
- changed testing and parameters
- some renaming

# Additional Context

closes #7308

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-08-28 19:46:45 +00:00

235 lines
6.2 KiB
Go

package query
import (
"context"
"database/sql"
"encoding/json"
"errors"
sq "github.com/Masterminds/squirrel"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
type UserSchemas struct {
SearchResponse
UserSchemas []*UserSchema
}
func (e *UserSchemas) SetState(s *State) {
e.State = s
}
type UserSchema struct {
domain.ObjectDetails
State domain.UserSchemaState
Type string
Revision uint32
Schema json.RawMessage
PossibleAuthenticators database.NumberArray[domain.AuthenticatorType]
}
type UserSchemaSearchQueries struct {
SearchRequest
Queries []SearchQuery
}
var (
userSchemaTable = table{
name: projection.UserSchemaTable,
instanceIDCol: projection.UserSchemaInstanceIDCol,
}
UserSchemaIDCol = Column{
name: projection.UserSchemaIDCol,
table: userSchemaTable,
}
UserSchemaCreationDateCol = Column{
name: projection.UserSchemaCreationDateCol,
table: userSchemaTable,
}
UserSchemaChangeDateCol = Column{
name: projection.UserSchemaChangeDateCol,
table: userSchemaTable,
}
UserSchemaInstanceIDCol = Column{
name: projection.UserSchemaInstanceIDCol,
table: userSchemaTable,
}
UserSchemaSequenceCol = Column{
name: projection.UserSchemaSequenceCol,
table: userSchemaTable,
}
UserSchemaStateCol = Column{
name: projection.UserSchemaStateCol,
table: userSchemaTable,
}
UserSchemaTypeCol = Column{
name: projection.UserSchemaTypeCol,
table: userSchemaTable,
}
UserSchemaRevisionCol = Column{
name: projection.UserSchemaRevisionCol,
table: userSchemaTable,
}
UserSchemaSchemaCol = Column{
name: projection.UserSchemaSchemaCol,
table: userSchemaTable,
}
UserSchemaPossibleAuthenticatorsCol = Column{
name: projection.UserSchemaPossibleAuthenticatorsCol,
table: userSchemaTable,
}
)
func (q *Queries) GetUserSchemaByID(ctx context.Context, id string) (userSchema *UserSchema, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
eq := sq.Eq{
UserSchemaIDCol.identifier(): id,
UserSchemaInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
query, scan := prepareUserSchemaQuery()
return genericRowQuery[*UserSchema](ctx, q.client, query.Where(eq), scan)
}
func (q *Queries) SearchUserSchema(ctx context.Context, queries *UserSchemaSearchQueries) (userSchemas *UserSchemas, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
eq := sq.Eq{
UserSchemaInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
}
query, scan := prepareUserSchemasQuery()
return genericRowsQueryWithState[*UserSchemas](ctx, q.client, userSchemaTable, combineToWhereStmt(query, queries.toQuery, eq), scan)
}
func (q *UserSchemaSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
query = q.SearchRequest.toQuery(query)
for _, q := range q.Queries {
query = q.toQuery(query)
}
return query
}
func NewUserSchemaTypeSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
return NewTextQuery(UserSchemaTypeCol, value, comparison)
}
func NewUserSchemaIDSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
return NewTextQuery(UserSchemaIDCol, value, comparison)
}
func NewUserSchemaStateSearchQuery(value domain.UserSchemaState) (SearchQuery, error) {
return NewNumberQuery(UserSchemaStateCol, value, NumberEquals)
}
func prepareUserSchemaQuery() (sq.SelectBuilder, func(*sql.Row) (*UserSchema, error)) {
return sq.Select(
UserSchemaIDCol.identifier(),
UserSchemaCreationDateCol.identifier(),
UserSchemaChangeDateCol.identifier(),
UserSchemaSequenceCol.identifier(),
UserSchemaInstanceIDCol.identifier(),
UserSchemaStateCol.identifier(),
UserSchemaTypeCol.identifier(),
UserSchemaRevisionCol.identifier(),
UserSchemaSchemaCol.identifier(),
UserSchemaPossibleAuthenticatorsCol.identifier(),
).
From(userSchemaTable.identifier()).
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*UserSchema, error) {
u := new(UserSchema)
var schema database.ByteArray[byte]
err := row.Scan(
&u.ID,
&u.CreationDate,
&u.EventDate,
&u.Sequence,
&u.ResourceOwner,
&u.State,
&u.Type,
&u.Revision,
&schema,
&u.PossibleAuthenticators,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, zerrors.ThrowNotFound(err, "QUERY-SAF3t", "Errors.UserSchema.NotExists")
}
return nil, zerrors.ThrowInternal(err, "QUERY-WRB2Q", "Errors.Internal")
}
u.Schema = json.RawMessage(schema)
return u, nil
}
}
func prepareUserSchemasQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserSchemas, error)) {
return sq.Select(
UserSchemaIDCol.identifier(),
UserSchemaCreationDateCol.identifier(),
UserSchemaChangeDateCol.identifier(),
UserSchemaSequenceCol.identifier(),
UserSchemaInstanceIDCol.identifier(),
UserSchemaStateCol.identifier(),
UserSchemaTypeCol.identifier(),
UserSchemaRevisionCol.identifier(),
UserSchemaSchemaCol.identifier(),
UserSchemaPossibleAuthenticatorsCol.identifier(),
countColumn.identifier()).
From(userSchemaTable.identifier()).
PlaceholderFormat(sq.Dollar),
func(rows *sql.Rows) (*UserSchemas, error) {
schemas := make([]*UserSchema, 0)
var (
schema database.ByteArray[byte]
count uint64
)
for rows.Next() {
u := new(UserSchema)
err := rows.Scan(
&u.ID,
&u.CreationDate,
&u.EventDate,
&u.Sequence,
&u.ResourceOwner,
&u.State,
&u.Type,
&u.Revision,
&schema,
&u.PossibleAuthenticators,
&count,
)
if err != nil {
return nil, err
}
u.Schema = json.RawMessage(schema)
schemas = append(schemas, u)
}
if err := rows.Close(); err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-Lwj2e", "Errors.Query.CloseRows")
}
return &UserSchemas{
UserSchemas: schemas,
SearchResponse: SearchResponse{
Count: count,
},
}, nil
}
}