mirror of
https://github.com/PrivateCaptcha/PrivateCaptcha.git
synced 2026-05-03 11:31:35 -05:00
604 lines
19 KiB
Go
604 lines
19 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/PrivateCaptcha/PrivateCaptcha/pkg/common"
|
|
dbgen "github.com/PrivateCaptcha/PrivateCaptcha/pkg/db/generated"
|
|
)
|
|
|
|
type AuditLog struct {
|
|
querier dbgen.Querier
|
|
persistChan chan *common.AuditLogEvent
|
|
persistCancel context.CancelFunc
|
|
batchSize int
|
|
}
|
|
|
|
var _ common.AuditLog = (*AuditLog)(nil)
|
|
|
|
func NewAuditLog(querier dbgen.Querier, batchSize int) *AuditLog {
|
|
return &AuditLog{
|
|
querier: querier,
|
|
persistChan: make(chan *common.AuditLogEvent, batchSize),
|
|
persistCancel: func() {},
|
|
batchSize: batchSize,
|
|
}
|
|
}
|
|
|
|
func (al *AuditLog) Start(ctx context.Context, interval time.Duration) {
|
|
var cancelCtx context.Context
|
|
cancelCtx, al.persistCancel = context.WithCancel(
|
|
context.WithValue(ctx, common.TraceIDContextKey, "persist_auditlog"))
|
|
go common.ProcessBatchArray(cancelCtx, al.persistChan, interval, al.batchSize, al.batchSize*10, al.persistAuditLog)
|
|
}
|
|
|
|
func (al *AuditLog) Shutdown() {
|
|
slog.Debug("Shutting down persisting sessions")
|
|
al.persistCancel()
|
|
close(al.persistChan)
|
|
}
|
|
|
|
func (al *AuditLog) persistAuditLog(ctx context.Context, batch []*common.AuditLogEvent) error {
|
|
dbBatch := make([]*dbgen.CreateAuditLogsParams, 0, len(batch))
|
|
|
|
for _, e := range batch {
|
|
action := dbgen.AuditLogActionUnknown
|
|
switch e.Action {
|
|
case common.AuditLogActionCreate:
|
|
action = dbgen.AuditLogActionCreate
|
|
case common.AuditLogActionUpdate:
|
|
action = dbgen.AuditLogActionUpdate
|
|
case common.AuditLogActionDelete:
|
|
action = dbgen.AuditLogActionDelete
|
|
case common.AuditLogActionSoftDelete:
|
|
action = dbgen.AuditLogActionSoftDelete
|
|
case common.AuditLogActionRecover:
|
|
action = dbgen.AuditLogActionRecover
|
|
case common.AuditLogActionLogin:
|
|
action = dbgen.AuditLogActionLogin
|
|
case common.AuditLogActionLogout:
|
|
action = dbgen.AuditLogActionLogout
|
|
case common.AuditLogActionAccess:
|
|
action = dbgen.AuditLogActionAccess
|
|
}
|
|
|
|
source := dbgen.AuditLogSourceUnknown
|
|
switch e.Source {
|
|
case common.AuditLogSourcePortal:
|
|
source = dbgen.AuditLogSourcePortal
|
|
case common.AuditLogSourceAPI:
|
|
source = dbgen.AuditLogSourceApi
|
|
}
|
|
|
|
event := &dbgen.CreateAuditLogsParams{
|
|
UserID: Int(e.UserID),
|
|
Action: action,
|
|
Source: source,
|
|
EntityID: Int8(e.EntityID),
|
|
EntityTable: e.TableName,
|
|
SessionID: e.SessionID,
|
|
OldValue: nil,
|
|
NewValue: nil,
|
|
CreatedAt: Timestampz(e.Timestamp),
|
|
}
|
|
|
|
if e.OldValue != nil {
|
|
if payload, err := json.Marshal(e.OldValue); err == nil {
|
|
event.OldValue = payload
|
|
} else {
|
|
slog.ErrorContext(ctx, "Failed to serialize old value for audit log", "table", e.TableName, "entityID", e.EntityID, common.ErrAttr(err))
|
|
}
|
|
}
|
|
|
|
if e.NewValue != nil {
|
|
if payload, err := json.Marshal(e.NewValue); err == nil {
|
|
event.NewValue = payload
|
|
} else {
|
|
slog.ErrorContext(ctx, "Failed to serialize new value for audit log", "table", e.TableName, "entityID", e.EntityID, common.ErrAttr(err))
|
|
}
|
|
}
|
|
|
|
dbBatch = append(dbBatch, event)
|
|
}
|
|
|
|
return al.storeAuditLogEvents(ctx, dbBatch)
|
|
}
|
|
|
|
func (al *AuditLog) storeAuditLogEvents(ctx context.Context, batch []*dbgen.CreateAuditLogsParams) error {
|
|
if len(batch) == 0 {
|
|
return nil
|
|
}
|
|
|
|
count, err := al.querier.CreateAuditLogs(ctx, batch)
|
|
if err != nil {
|
|
slog.ErrorContext(ctx, "Failed to store audit log events", "count", len(batch), common.ErrAttr(err))
|
|
return err
|
|
}
|
|
|
|
slog.InfoContext(ctx, "Stored audit log events", "count", len(batch), "rows", count)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (al *AuditLog) RecordEvents(ctx context.Context, events []*common.AuditLogEvent, source common.AuditLogSource) {
|
|
for _, event := range events {
|
|
al.RecordEvent(ctx, event, source)
|
|
}
|
|
}
|
|
|
|
func (al *AuditLog) RecordEvent(ctx context.Context, event *common.AuditLogEvent, source common.AuditLogSource) {
|
|
if event == nil {
|
|
slog.ErrorContext(ctx, "Discarding nil audit log event")
|
|
return
|
|
}
|
|
|
|
if (event.OldValue == nil) && (event.NewValue == nil) &&
|
|
(event.Action != common.AuditLogActionAccess) &&
|
|
(event.Action != common.AuditLogActionLogin) &&
|
|
(event.Action != common.AuditLogActionLogout) {
|
|
slog.WarnContext(ctx, "Audit log event has no payload", "table", event.TableName, "entityID", event.EntityID, "action", event.Action.String())
|
|
}
|
|
|
|
if event.UserID == 0 {
|
|
slog.ErrorContext(ctx, "Recording audit event without user ID", "table", event.TableName, "entityID", event.EntityID, "action", event.Action.String())
|
|
}
|
|
|
|
if sid, ok := ctx.Value(common.SessionIDContextKey).(string); ok && (len(sid) > 0) {
|
|
event.SessionID = sid
|
|
}
|
|
|
|
event.Timestamp = time.Now().UTC()
|
|
event.Source = source
|
|
|
|
slog.DebugContext(ctx, "Queueing audit log event", "action", event.Action.String(), "table", event.TableName, "userID", event.UserID, "source", source.String())
|
|
al.persistChan <- event
|
|
}
|
|
|
|
type DiscardAuditLog struct{}
|
|
|
|
var _ common.AuditLog = (*DiscardAuditLog)(nil)
|
|
|
|
func (dal *DiscardAuditLog) RecordEvents(ctx context.Context, events []*common.AuditLogEvent, source common.AuditLogSource) {
|
|
for _, event := range events {
|
|
dal.RecordEvent(ctx, event, source)
|
|
}
|
|
}
|
|
|
|
func (dal *DiscardAuditLog) RecordEvent(ctx context.Context, event *common.AuditLogEvent, source common.AuditLogSource) {
|
|
slog.WarnContext(ctx, "Discarded audit log event", "table", event.TableName, "entityID", event.EntityID, "action", event.Action)
|
|
}
|
|
|
|
func ParseAuditLogPayloads[T any](ctx context.Context, log *dbgen.AuditLog) (*T, *T, error) {
|
|
var tOld *T
|
|
if len(log.OldValue) > 0 {
|
|
tOld = new(T)
|
|
if err := json.Unmarshal(log.OldValue, tOld); err != nil {
|
|
slog.ErrorContext(ctx, "Failed to parse audit log old value", "table", log.EntityTable, "action", log.Action,
|
|
"length", len(log.OldValue), common.ErrAttr(err))
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
var tNew *T
|
|
if len(log.NewValue) > 0 {
|
|
tNew = new(T)
|
|
if err := json.Unmarshal(log.NewValue, tNew); err != nil {
|
|
slog.ErrorContext(ctx, "Failed to parse audit log new value", "table", log.EntityTable, "action", log.Action,
|
|
"length", len(log.OldValue), common.ErrAttr(err))
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
return tOld, tNew, nil
|
|
}
|
|
|
|
type AuditLogUser struct {
|
|
Name string `json:"name,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
SubscriptionID int32 `json:"subscription_id,omitempty"`
|
|
}
|
|
|
|
func newAuditLogUser(user *dbgen.User) *AuditLogUser {
|
|
return &AuditLogUser{
|
|
Name: user.Name,
|
|
Email: user.Email,
|
|
SubscriptionID: user.SubscriptionID.Int32,
|
|
}
|
|
}
|
|
|
|
type AuditLogSubscription struct {
|
|
Source string `json:"source,omitempty"`
|
|
Status string `json:"status,omitempty"`
|
|
ExternalProductID string `json:"external_product_id,omitempty"`
|
|
ExternalSubscriptionID string `json:"external_subscription_id,omitempty"`
|
|
ExternalPriceID string `json:"external_price_id,omitempty"`
|
|
CancelAt common.JSONTime `json:"cancel_at,omitempty"`
|
|
}
|
|
|
|
func newAuditLogSubscription(subscription *dbgen.Subscription) *AuditLogSubscription {
|
|
log := &AuditLogSubscription{
|
|
Source: string(subscription.Source),
|
|
Status: subscription.Status,
|
|
ExternalProductID: subscription.ExternalProductID,
|
|
ExternalSubscriptionID: subscription.ExternalSubscriptionID.String,
|
|
ExternalPriceID: subscription.ExternalPriceID,
|
|
CancelAt: common.JSONTime{},
|
|
}
|
|
|
|
if subscription.CancelFrom.Valid {
|
|
log.CancelAt = common.JSONTime(subscription.CancelFrom.Time)
|
|
}
|
|
|
|
return log
|
|
}
|
|
|
|
func newUserAuditLogEvent(user *dbgen.User, subscription *dbgen.Subscription, action common.AuditLogAction) *common.AuditLogEvent {
|
|
event := &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: action,
|
|
EntityID: int64(user.ID),
|
|
TableName: TableNameUsers,
|
|
OldValue: nil,
|
|
NewValue: nil,
|
|
}
|
|
|
|
switch action {
|
|
case common.AuditLogActionCreate, common.AuditLogActionRecover:
|
|
event.NewValue = newAuditLogUser(user)
|
|
case common.AuditLogActionDelete, common.AuditLogActionSoftDelete:
|
|
event.OldValue = newAuditLogUser(user)
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func newUpdateUserSubscriptionEvent(user *dbgen.User, oldSubscription, newSubscription *dbgen.Subscription) *common.AuditLogEvent {
|
|
event := &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(newSubscription.ID),
|
|
TableName: TableNameSubscriptions,
|
|
NewValue: newAuditLogSubscription(newSubscription),
|
|
}
|
|
|
|
if oldSubscription != nil {
|
|
event.OldValue = newAuditLogSubscription(oldSubscription)
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func newUpdateUserAuditLogEvent(oldUser *dbgen.User, newUser *dbgen.User) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: oldUser.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(oldUser.ID),
|
|
TableName: TableNameUsers,
|
|
OldValue: newAuditLogUser(oldUser),
|
|
NewValue: newAuditLogUser(newUser),
|
|
}
|
|
}
|
|
|
|
type AuditLogOrg struct {
|
|
ID int32 `json:"id"`
|
|
Name string `json:"name"`
|
|
NewOwnerID int32 `json:"new_owner_id,omitempty"`
|
|
NewOwnerEmail string `json:"new_owner_email,omitempty"`
|
|
}
|
|
|
|
func NewAuditLogOrg(org *dbgen.Organization) *AuditLogOrg {
|
|
return &AuditLogOrg{
|
|
ID: org.ID,
|
|
Name: org.Name,
|
|
}
|
|
}
|
|
|
|
func newOrgAuditLogEvent(userID int32, org *dbgen.Organization, action common.AuditLogAction) *common.AuditLogEvent {
|
|
event := &common.AuditLogEvent{
|
|
UserID: userID,
|
|
Action: action,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgs,
|
|
OldValue: nil,
|
|
NewValue: nil,
|
|
}
|
|
|
|
switch action {
|
|
case common.AuditLogActionCreate, common.AuditLogActionRecover:
|
|
event.NewValue = NewAuditLogOrg(org)
|
|
case common.AuditLogActionDelete, common.AuditLogActionSoftDelete:
|
|
event.OldValue = NewAuditLogOrg(org)
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
type AuditLogProperty struct {
|
|
Name string `json:"name,omitempty"`
|
|
OrgID int32 `json:"org_id,omitempty"`
|
|
OrgName string `json:"org_name,omitempty"`
|
|
OrgOwnerID int32 `json:"org_owner_id,omitempty"`
|
|
CreatorID int32 `json:"creator_id,omitempty"`
|
|
Domain string `json:"domain,omitempty"`
|
|
Level int16 `json:"level,omitempty"`
|
|
Growth string `json:"growth,omitempty"`
|
|
ValidityIntervalSec int `json:"validity_interval_s,omitempty"`
|
|
MaxReplayCount int32 `json:"max_replay_count,omitempty"`
|
|
AllowSubdomains bool `json:"allow_subdomains,omitempty"`
|
|
AllowLocalhost bool `json:"allow_localhost,omitempty"`
|
|
}
|
|
|
|
func newAuditLogProperty(property *dbgen.Property, org *dbgen.Organization) *AuditLogProperty {
|
|
if property == nil {
|
|
return nil
|
|
}
|
|
|
|
event := &AuditLogProperty{
|
|
Name: property.Name,
|
|
OrgID: property.OrgID.Int32,
|
|
OrgOwnerID: property.OrgOwnerID.Int32,
|
|
CreatorID: property.CreatorID.Int32,
|
|
Domain: property.Domain,
|
|
Level: property.Level.Int16,
|
|
Growth: string(property.Growth),
|
|
ValidityIntervalSec: int(property.ValidityInterval.Seconds()),
|
|
MaxReplayCount: property.MaxReplayCount,
|
|
AllowSubdomains: property.AllowSubdomains,
|
|
AllowLocalhost: property.AllowLocalhost,
|
|
}
|
|
|
|
if org != nil {
|
|
event.OrgName = org.Name
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func newAuditLogOldProperty(property *dbgen.Property, updateRow *dbgen.UpdatePropertyRow, org *dbgen.Organization) *AuditLogProperty {
|
|
if updateRow == nil {
|
|
return nil
|
|
}
|
|
|
|
event := &AuditLogProperty{
|
|
Name: updateRow.OldName,
|
|
OrgID: property.OrgID.Int32,
|
|
OrgOwnerID: property.OrgOwnerID.Int32,
|
|
CreatorID: property.CreatorID.Int32,
|
|
Domain: property.Domain,
|
|
Level: updateRow.OldLevel.Int16,
|
|
Growth: string(updateRow.OldGrowth),
|
|
ValidityIntervalSec: int(updateRow.OldValidityInterval.Seconds()),
|
|
MaxReplayCount: updateRow.OldMaxReplayCount,
|
|
AllowSubdomains: updateRow.OldAllowSubdomains,
|
|
AllowLocalhost: updateRow.OldAllowLocalhost,
|
|
}
|
|
|
|
if org != nil {
|
|
event.OrgName = org.Name
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func newCreatePropertyAuditLogEvent(property *dbgen.Property, org *dbgen.Organization) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: property.CreatorID.Int32,
|
|
Action: common.AuditLogActionCreate,
|
|
EntityID: int64(property.ID),
|
|
TableName: TableNameProperties,
|
|
OldValue: nil,
|
|
NewValue: newAuditLogProperty(property, org),
|
|
}
|
|
}
|
|
|
|
func newUpdatePropertyAuditLogEvent(updatedProperty *dbgen.Property, updateRow *dbgen.UpdatePropertyRow, org *dbgen.Organization, user *dbgen.User) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(updatedProperty.ID),
|
|
TableName: TableNameProperties,
|
|
OldValue: newAuditLogOldProperty(updatedProperty, updateRow, org),
|
|
NewValue: newAuditLogProperty(updatedProperty, org),
|
|
}
|
|
}
|
|
|
|
func newDeletePropertyAuditLogEvent(property *dbgen.Property, org *dbgen.Organization, user *dbgen.User) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionSoftDelete,
|
|
EntityID: int64(property.ID),
|
|
TableName: TableNameProperties,
|
|
OldValue: newAuditLogProperty(property, org),
|
|
NewValue: nil,
|
|
}
|
|
}
|
|
|
|
func newUpdateOrgAuditLogEvent(user *dbgen.User, org *dbgen.Organization, oldName string) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgs,
|
|
OldValue: &AuditLogOrg{Name: oldName},
|
|
NewValue: &AuditLogOrg{Name: org.Name},
|
|
}
|
|
}
|
|
|
|
func newTransferOrgAuditLogEvent(user *dbgen.User, org *dbgen.Organization, newOwner *dbgen.User) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgs,
|
|
OldValue: NewAuditLogOrg(org),
|
|
NewValue: &AuditLogOrg{ID: org.ID, Name: org.Name, NewOwnerID: newOwner.ID, NewOwnerEmail: newOwner.Email},
|
|
}
|
|
}
|
|
|
|
type AuditLogOrgUser struct {
|
|
OrgName string `json:"org_name,omitempty"`
|
|
UserID int32 `json:"user_id,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
Level string `json:"level,omitempty"`
|
|
}
|
|
|
|
func newAuditLogOrgUser(user *dbgen.User, orgName string, level string) *AuditLogOrgUser {
|
|
return &AuditLogOrgUser{
|
|
OrgName: orgName,
|
|
UserID: user.ID,
|
|
Email: user.Email,
|
|
Level: level,
|
|
}
|
|
}
|
|
|
|
func newOrgInviteAuditLogEvent(user *dbgen.User, org *dbgen.Organization, inviteUser *dbgen.User) *common.AuditLogEvent {
|
|
// this one is bit tough (we kind of need 1 more "entity id" field), but our logic is that for audit log we record
|
|
// "who did what with what" so org owner invited to org <user>
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionCreate,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgUsers,
|
|
OldValue: nil,
|
|
NewValue: newAuditLogOrgUser(inviteUser, org.Name, string(dbgen.AccessLevelInvited)),
|
|
}
|
|
}
|
|
|
|
func newOrgEmailInviteAuditLogEvent(user *dbgen.User, org *dbgen.Organization, inviteEmail string) *common.AuditLogEvent {
|
|
// Similar to newOrgInviteAuditLogEvent but for email-only invites where user doesn't exist yet
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionCreate,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgUsers,
|
|
OldValue: nil,
|
|
NewValue: &AuditLogOrgUser{OrgName: org.Name, Email: inviteEmail, Level: string(dbgen.AccessLevelInvited)},
|
|
}
|
|
}
|
|
|
|
func newOrgMemberDeleteAuditLogEvent(user *dbgen.User, org *dbgen.Organization, userID int32, email string) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionDelete,
|
|
EntityID: int64(org.ID),
|
|
TableName: TableNameOrgUsers,
|
|
OldValue: &AuditLogOrgUser{OrgName: org.Name, UserID: userID, Email: email},
|
|
NewValue: nil,
|
|
}
|
|
}
|
|
|
|
func newOrgMemberAuditLogEvent(orgID int32, orgName string, user *dbgen.User, action common.AuditLogAction, level string) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: action,
|
|
EntityID: int64(orgID),
|
|
TableName: TableNameOrgUsers,
|
|
OldValue: nil,
|
|
NewValue: newAuditLogOrgUser(user, orgName, level),
|
|
}
|
|
}
|
|
|
|
func newOrgOwnershipSwapAuditLogEvent(orgID int32, orgName string, actor *dbgen.User, oldOwner *dbgen.User, newOwner *dbgen.User) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: actor.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(orgID),
|
|
TableName: TableNameOrgUsers,
|
|
OldValue: newAuditLogOrgUser(newOwner, orgName, string(dbgen.AccessLevelMember)),
|
|
NewValue: newAuditLogOrgUser(oldOwner, orgName, string(dbgen.AccessLevelMember)),
|
|
}
|
|
}
|
|
|
|
type AuditLogAPIKey struct {
|
|
Name string `json:"name,omitempty"`
|
|
ExternalID string `json:"external_id,omitempty"`
|
|
Enabled bool `json:"enabled,omitempty"`
|
|
RequestsPerSecond float64 `json:"requests_per_second,omitempty"`
|
|
RequestsBurst int32 `json:"requests_burst,omitempty"`
|
|
ExpiresAt common.JSONTime `json:"expires_at,omitempty"`
|
|
Notes string `json:"notes,omitempty"`
|
|
Period time.Duration `json:"period,omitempty"`
|
|
Scope string `json:"scope,omitempty"`
|
|
OrgName string `json:"org_name,omitempty"`
|
|
ReadOnly bool `json:"readonly,omitempty"`
|
|
}
|
|
|
|
func newAuditLogAPIKey(key *dbgen.APIKey, orgName string) *AuditLogAPIKey {
|
|
if key == nil {
|
|
return nil
|
|
}
|
|
|
|
return &AuditLogAPIKey{
|
|
Name: key.Name,
|
|
ExternalID: UUIDToSecret(key.ExternalID),
|
|
Enabled: key.Enabled.Bool,
|
|
RequestsPerSecond: key.RequestsPerSecond,
|
|
RequestsBurst: key.RequestsBurst,
|
|
ExpiresAt: common.JSONTime(key.ExpiresAt.Time),
|
|
Notes: key.Notes.String,
|
|
Period: key.Period,
|
|
Scope: string(key.Scope),
|
|
OrgName: orgName,
|
|
ReadOnly: key.Readonly,
|
|
}
|
|
}
|
|
|
|
func newAPIKeyAuditLogEvent(user *dbgen.User, apiKey *dbgen.APIKey, action common.AuditLogAction, orgName string) *common.AuditLogEvent {
|
|
event := &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: action,
|
|
EntityID: int64(apiKey.ID),
|
|
TableName: TableNameAPIKeys,
|
|
OldValue: nil,
|
|
NewValue: nil,
|
|
}
|
|
|
|
switch action {
|
|
case common.AuditLogActionCreate, common.AuditLogActionRecover:
|
|
event.NewValue = newAuditLogAPIKey(apiKey, orgName)
|
|
case common.AuditLogActionDelete, common.AuditLogActionSoftDelete:
|
|
event.OldValue = newAuditLogAPIKey(apiKey, orgName)
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func newUpdateAPIKeyAuditLogEvent(user *dbgen.User, oldAPIKey, newAPIKey *dbgen.APIKey) *common.AuditLogEvent {
|
|
if (oldAPIKey == nil) && (newAPIKey == nil) {
|
|
return nil
|
|
}
|
|
|
|
entityKey := oldAPIKey
|
|
if entityKey == nil {
|
|
entityKey = newAPIKey
|
|
}
|
|
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(entityKey.ID),
|
|
TableName: TableNameAPIKeys,
|
|
OldValue: newAuditLogAPIKey(oldAPIKey, ""),
|
|
NewValue: newAuditLogAPIKey(newAPIKey, ""),
|
|
}
|
|
}
|
|
|
|
func newMovePropertyAuditLogEvent(user *dbgen.User, property *dbgen.Property, oldOrgID, newOrgID int32) *common.AuditLogEvent {
|
|
return &common.AuditLogEvent{
|
|
UserID: user.ID,
|
|
Action: common.AuditLogActionUpdate,
|
|
EntityID: int64(property.ID),
|
|
TableName: TableNameProperties,
|
|
OldValue: &AuditLogProperty{OrgID: oldOrgID},
|
|
NewValue: &AuditLogProperty{OrgID: newOrgID},
|
|
}
|
|
}
|
|
|
|
type AuditLogAccess struct {
|
|
View string `json:"view,omitempty"`
|
|
EntityName string `json:"name,omitempty"`
|
|
}
|