zitadel/internal/query/limits.go
Elio Bischof 385a55bd21
feat: limit audit trail (#6744)
* feat: enable limiting audit trail

* support AddExclusiveQuery

* fix invalid condition

* register event mappers

* fix NullDuration validity

* test query side for limits

* lint

* acceptance test audit trail limit

* fix acceptance test

* translate limits not found

* update tests

* fix linting

* add audit log retention to default instance

* fix tests

* update docs

* remove todo

* improve test name
2023-10-25 11:42:00 +00:00

120 lines
3.3 KiB
Go

package query
import (
"context"
"database/sql"
errs "errors"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/call"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
)
var (
limitSettingsTable = table{
name: projection.LimitsProjectionTable,
instanceIDCol: projection.LimitsColumnInstanceID,
}
LimitsColumnAggregateID = Column{
name: projection.LimitsColumnAggregateID,
table: limitSettingsTable,
}
LimitsColumnCreationDate = Column{
name: projection.LimitsColumnCreationDate,
table: limitSettingsTable,
}
LimitsColumnChangeDate = Column{
name: projection.LimitsColumnChangeDate,
table: limitSettingsTable,
}
LimitsColumnResourceOwner = Column{
name: projection.LimitsColumnResourceOwner,
table: limitSettingsTable,
}
LimitsColumnInstanceID = Column{
name: projection.LimitsColumnInstanceID,
table: limitSettingsTable,
}
LimitsColumnSequence = Column{
name: projection.LimitsColumnSequence,
table: limitSettingsTable,
}
LimitsColumnAuditLogRetention = Column{
name: projection.LimitsColumnAuditLogRetention,
table: limitSettingsTable,
}
)
type Limits struct {
AggregateID string
CreationDate time.Time
ChangeDate time.Time
ResourceOwner string
Sequence uint64
AuditLogRetention *time.Duration
}
func (q *Queries) Limits(ctx context.Context, resourceOwner string) (limits *Limits, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareLimitsQuery(ctx, q.client)
query, args, err := stmt.Where(sq.Eq{
LimitsColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
LimitsColumnResourceOwner.identifier(): resourceOwner,
}).ToSql()
if err != nil {
return nil, errors.ThrowInternal(err, "QUERY-jJe80", "Errors.Query.SQLStatment")
}
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
limits, err = scan(row)
return err
}, query, args...)
return limits, err
}
func prepareLimitsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*Limits, error)) {
return sq.Select(
LimitsColumnAggregateID.identifier(),
LimitsColumnCreationDate.identifier(),
LimitsColumnChangeDate.identifier(),
LimitsColumnResourceOwner.identifier(),
LimitsColumnSequence.identifier(),
LimitsColumnAuditLogRetention.identifier(),
).
From(limitSettingsTable.identifier() + db.Timetravel(call.Took(ctx))).
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*Limits, error) {
var (
limits = new(Limits)
auditLogRetention database.NullDuration
)
err := row.Scan(
&limits.AggregateID,
&limits.CreationDate,
&limits.ChangeDate,
&limits.ResourceOwner,
&limits.Sequence,
&auditLogRetention,
)
if err != nil {
if errs.Is(err, sql.ErrNoRows) {
return nil, errors.ThrowNotFound(err, "QUERY-GU1em", "Errors.Limits.NotFound")
}
return nil, errors.ThrowInternal(err, "QUERY-00jgy", "Errors.Internal")
}
if auditLogRetention.Valid {
limits.AuditLogRetention = &auditLogRetention.Duration
}
return limits, nil
}
}