diff --git a/pkg/audit/listener.go b/pkg/audit/listener.go index c0454512a..599a9b385 100644 --- a/pkg/audit/listener.go +++ b/pkg/audit/listener.go @@ -45,27 +45,15 @@ func RegisterEventForAudit[T any, PT interface { events.Event }](toEntry func(PT) *Entry) { name := PT(new(T)).Name() - RegisterEventNameForAudit(name, func(payload []byte) (*Entry, error) { - e := PT(new(T)) // fresh instance per message — handlers run concurrently - if err := json.Unmarshal(payload, e); err != nil { - return nil, err - } - return toEntry(e), nil - }) -} - -// RegisterEventNameForAudit is the untyped variant for events which cannot be -// unmarshaled into their Go struct directly (e.g. interface-typed Doer -// fields); the mapping decodes the raw payload itself. -func RegisterEventNameForAudit(name string, toEntry func(payload []byte) (*Entry, error)) { events.RegisterListener(name, &auditListener{handle: func(msg *message.Message) error { if !license.IsFeatureEnabled(license.FeatureAuditLogs) { return nil // license is runtime-mutable — checked per event, not at registration } - entry, err := toEntry(msg.Payload) - if err != nil { + e := PT(new(T)) // fresh instance per message — handlers run concurrently + if err := json.Unmarshal(msg.Payload, e); err != nil { return err } + entry := toEntry(e) if entry == nil { return nil } diff --git a/pkg/models/events.go b/pkg/models/events.go index 1996f54b8..b938345f4 100644 --- a/pkg/models/events.go +++ b/pkg/models/events.go @@ -18,7 +18,6 @@ package models import ( "code.vikunja.io/api/pkg/user" - "code.vikunja.io/api/pkg/web" ) ///////////////// @@ -230,8 +229,8 @@ func (l *ProjectCreatedEvent) Name() string { // ProjectUpdatedEvent represents an event where a project has been updated type ProjectUpdatedEvent struct { - Project *Project `json:"project"` - Doer web.Auth `json:"doer"` + Project *Project `json:"project"` + Doer *user.User `json:"doer"` } // Name defines the name for ProjectUpdatedEvent @@ -241,8 +240,8 @@ func (p *ProjectUpdatedEvent) Name() string { // ProjectDeletedEvent represents an event where a project has been deleted type ProjectDeletedEvent struct { - Project *Project `json:"project"` - Doer web.Auth `json:"doer"` + Project *Project `json:"project"` + Doer *user.User `json:"doer"` } // Name defines the name for ProjectDeletedEvent @@ -258,7 +257,7 @@ func (p *ProjectDeletedEvent) Name() string { type ProjectSharedWithUserEvent struct { Project *Project `json:"project"` User *user.User `json:"user"` - Doer web.Auth `json:"doer"` + Doer *user.User `json:"doer"` } // Name defines the name for ProjectSharedWithUserEvent @@ -268,9 +267,9 @@ func (p *ProjectSharedWithUserEvent) Name() string { // ProjectSharedWithTeamEvent represents an event where a project has been shared with a team type ProjectSharedWithTeamEvent struct { - Project *Project `json:"project"` - Team *Team `json:"team"` - Doer web.Auth `json:"doer"` + Project *Project `json:"project"` + Team *Team `json:"team"` + Doer *user.User `json:"doer"` } // Name defines the name for ProjectSharedWithTeamEvent @@ -308,8 +307,8 @@ func (t *TeamMemberRemovedEvent) Name() string { // TeamCreatedEvent represents a TeamCreatedEvent event type TeamCreatedEvent struct { - Team *Team `json:"team"` - Doer web.Auth `json:"doer"` + Team *Team `json:"team"` + Doer *user.User `json:"doer"` } // Name defines the name for TeamCreatedEvent @@ -319,8 +318,8 @@ func (t *TeamCreatedEvent) Name() string { // TeamDeletedEvent represents a TeamDeletedEvent event type TeamDeletedEvent struct { - Team *Team `json:"team"` - Doer web.Auth `json:"doer"` + Team *Team `json:"team"` + Doer *user.User `json:"doer"` } // Name defines the name for TeamDeletedEvent diff --git a/pkg/models/listeners.go b/pkg/models/listeners.go index e29bb2369..e50631ae1 100644 --- a/pkg/models/listeners.go +++ b/pkg/models/listeners.go @@ -88,23 +88,6 @@ func RegisterListeners() { } } -// auditDoerRef decodes the doer of events whose Doer field is an interface -// and thus can't be unmarshaled into the event struct directly. -type auditDoerRef struct { - ID int64 `json:"id"` - Hash string `json:"hash"` // only set when the doer is a link share -} - -func auditActorFromDoerRef(d *auditDoerRef) audit.Actor { - if d == nil { - return audit.SystemActor() - } - if d.Hash != "" { - return audit.LinkShareActor(d.ID) - } - return audit.ActorFromDoerID(d.ID) -} - func auditActorFromUser(u *user.User) audit.Actor { if u == nil { return audit.SystemActor() @@ -281,95 +264,51 @@ func registerEventsForAuditLogging() { Target: audit.ProjectTarget(e.Project.ID), } }) - audit.RegisterEventNameForAudit((&ProjectUpdatedEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Project *Project `json:"project"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err - } + audit.RegisterEventForAudit(func(e *ProjectUpdatedEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionProjectUpdated, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.ProjectTarget(e.Project.ID), - }, nil - }) - audit.RegisterEventNameForAudit((&ProjectDeletedEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Project *Project `json:"project"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err } + }) + audit.RegisterEventForAudit(func(e *ProjectDeletedEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionProjectDeleted, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.ProjectTarget(e.Project.ID), - }, nil - }) - audit.RegisterEventNameForAudit((&ProjectSharedWithUserEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Project *Project `json:"project"` - User *user.User `json:"user"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err } + }) + audit.RegisterEventForAudit(func(e *ProjectSharedWithUserEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionProjectSharedWithUser, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.ProjectTarget(e.Project.ID), Metadata: map[string]any{"user_id": e.User.ID}, - }, nil - }) - audit.RegisterEventNameForAudit((&ProjectSharedWithTeamEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Project *Project `json:"project"` - Team *Team `json:"team"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err } + }) + audit.RegisterEventForAudit(func(e *ProjectSharedWithTeamEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionProjectSharedWithTeam, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.ProjectTarget(e.Project.ID), Metadata: map[string]any{"team_id": e.Team.ID}, - }, nil + } }) // Teams - audit.RegisterEventNameForAudit((&TeamCreatedEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Team *Team `json:"team"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err - } + audit.RegisterEventForAudit(func(e *TeamCreatedEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionTeamCreated, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.TeamTarget(e.Team.ID), - }, nil - }) - audit.RegisterEventNameForAudit((&TeamDeletedEvent{}).Name(), func(payload []byte) (*audit.Entry, error) { - e := &struct { - Team *Team `json:"team"` - Doer *auditDoerRef `json:"doer"` - }{} - if err := json.Unmarshal(payload, e); err != nil { - return nil, err } + }) + audit.RegisterEventForAudit(func(e *TeamDeletedEvent) *audit.Entry { return &audit.Entry{ Action: audit.ActionTeamDeleted, - Actor: auditActorFromDoerRef(e.Doer), + Actor: auditActorFromUser(e.Doer), Target: audit.TeamTarget(e.Team.ID), - }, nil + } }) audit.RegisterEventForAudit(func(e *TeamMemberAddedEvent) *audit.Entry { return &audit.Entry{ diff --git a/pkg/models/project.go b/pkg/models/project.go index 23fc9f6ca..019afe792 100644 --- a/pkg/models/project.go +++ b/pkg/models/project.go @@ -1217,9 +1217,13 @@ func UpdateProject(s *xorm.Session, project *Project, auth web.Auth, updateProje return err } + doer, err := GetUserOrLinkShareUser(s, auth) + if err != nil { + return err + } events.DispatchOnCommit(s, &ProjectUpdatedEvent{ Project: project, - Doer: auth, + Doer: doer, }) l, err := GetProjectSimpleByID(s, project.ID) @@ -1448,9 +1452,13 @@ func (p *Project) Delete(s *xorm.Session, a web.Auth) (err error) { return } + doer, err := GetUserOrLinkShareUser(s, a) + if err != nil { + return err + } events.DispatchOnCommit(s, &ProjectDeletedEvent{ Project: fullProject, - Doer: a, + Doer: doer, }) childProjects := []*Project{} diff --git a/pkg/models/project_team.go b/pkg/models/project_team.go index 0c9fb6908..4f3ed9c42 100644 --- a/pkg/models/project_team.go +++ b/pkg/models/project_team.go @@ -109,10 +109,14 @@ func (tl *TeamProject) Create(s *xorm.Session, a web.Auth) (err error) { return err } + doer, err := GetUserOrLinkShareUser(s, a) + if err != nil { + return err + } events.DispatchOnCommit(s, &ProjectSharedWithTeamEvent{ Project: l, Team: team, - Doer: a, + Doer: doer, }) err = updateProjectLastUpdated(s, l) diff --git a/pkg/models/project_users.go b/pkg/models/project_users.go index 58ef71c38..1470dd1bb 100644 --- a/pkg/models/project_users.go +++ b/pkg/models/project_users.go @@ -115,10 +115,14 @@ func (lu *ProjectUser) Create(s *xorm.Session, a web.Auth) (err error) { return err } + doer, err := GetUserOrLinkShareUser(s, a) + if err != nil { + return err + } events.DispatchOnCommit(s, &ProjectSharedWithUserEvent{ Project: l, User: u, - Doer: a, + Doer: doer, }) err = updateProjectLastUpdated(s, l) diff --git a/pkg/models/teams.go b/pkg/models/teams.go index 98c87161c..e1ac8887c 100644 --- a/pkg/models/teams.go +++ b/pkg/models/teams.go @@ -222,7 +222,7 @@ func (t *Team) CreateNewTeam(s *xorm.Session, a web.Auth, firstUserShouldBeAdmin events.DispatchOnCommit(s, &TeamCreatedEvent{ Team: t, - Doer: a, + Doer: doer, }) return nil } @@ -360,9 +360,13 @@ func (t *Team) Delete(s *xorm.Session, a web.Auth) (err error) { return } + doer, err := GetUserOrLinkShareUser(s, a) + if err != nil { + return err + } events.DispatchOnCommit(s, &TeamDeletedEvent{ Team: t, - Doer: a, + Doer: doer, }) return nil }