diff --git a/management/server/account.go b/management/server/account.go index 9177c2ce7..7e8d89571 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -42,7 +42,7 @@ type AccountManager interface { CreateSetupKey(accountID string, keyName string, keyType SetupKeyType, expiresIn time.Duration, autoGroups []string, usageLimit int) (*SetupKey, error) SaveSetupKey(accountID string, key *SetupKey) (*SetupKey, error) - CreateUser(accountID string, key *UserInfo) (*UserInfo, error) + CreateUser(accountID, userID string, key *UserInfo) (*UserInfo, error) ListSetupKeys(accountID, userID string) ([]*SetupKey, error) SaveUser(accountID string, key *User) (*UserInfo, error) GetSetupKey(accountID, userID, keyID string) (*SetupKey, error) diff --git a/management/server/account_test.go b/management/server/account_test.go index 31480eb5d..80052875d 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -3,6 +3,7 @@ package server import ( "fmt" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/route" "net" "reflect" @@ -1228,7 +1229,11 @@ func createManager(t *testing.T) (*DefaultAccountManager, error) { if err != nil { return nil, err } - return BuildManager(store, NewPeersUpdateManager(), nil, "", "") + eventStore, err := activity.NewSQLiteStore(t.TempDir()) + if err != nil { + return nil, err + } + return BuildManager(store, NewPeersUpdateManager(), nil, "", "", eventStore) } func createStore(t *testing.T) (Store, error) { diff --git a/management/server/activity/event.go b/management/server/activity/event.go index 85fc4d3a5..f20d4cfe8 100644 --- a/management/server/activity/event.go +++ b/management/server/activity/event.go @@ -17,7 +17,7 @@ const ( const ( // PeerAddedByUserMessage is a human-readable text message of the PeerAddedByUser activity - PeerAddedByUserMessage string = "New peer added by a user" + PeerAddedByUserMessage string = "User added a new peer" // PeerAddedWithSetupKeyMessage is a human-readable text message of the PeerAddedWithSetupKey activity PeerAddedWithSetupKeyMessage = "New peer added with a setup key" //UserJoinedMessage is a human-readable text message of the UserJoined activity diff --git a/management/server/http/users.go b/management/server/http/users.go index 698bb9410..7772e4f0f 100644 --- a/management/server/http/users.go +++ b/management/server/http/users.go @@ -81,7 +81,7 @@ func (h *UserHandler) CreateUserHandler(w http.ResponseWriter, r *http.Request) } claims := h.jwtExtractor.ExtractClaimsFromRequestContext(r, h.authAudience) - account, _, err := h.accountManager.GetAccountFromToken(claims) + account, user, err := h.accountManager.GetAccountFromToken(claims) if err != nil { util.WriteError(err, w) return @@ -99,7 +99,7 @@ func (h *UserHandler) CreateUserHandler(w http.ResponseWriter, r *http.Request) return } - newUser, err := h.accountManager.CreateUser(account.Id, &server.UserInfo{ + newUser, err := h.accountManager.CreateUser(account.Id, user.Id, &server.UserInfo{ Email: req.Email, Name: *req.Name, Role: req.Role, diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index 8efeee33a..b50576fb5 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -3,6 +3,7 @@ package mock_server import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/jwtclaims" "github.com/netbirdio/netbird/route" "google.golang.org/grpc/codes" @@ -58,9 +59,10 @@ type MockAccountManager struct { UpdateNameServerGroupFunc func(accountID, nsGroupID string, operations []server.NameServerGroupUpdateOperation) (*nbdns.NameServerGroup, error) DeleteNameServerGroupFunc func(accountID, nsGroupID string) error ListNameServerGroupsFunc func(accountID string) ([]*nbdns.NameServerGroup, error) - CreateUserFunc func(accountID string, key *server.UserInfo) (*server.UserInfo, error) + CreateUserFunc func(accountID, userID string, key *server.UserInfo) (*server.UserInfo, error) GetAccountFromTokenFunc func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error) GetDNSDomainFunc func() string + GetEventsFunc func(accountID, userID string) ([]*activity.Event, error) } // GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface @@ -456,9 +458,9 @@ func (am *MockAccountManager) ListNameServerGroups(accountID string) ([]*nbdns.N } // CreateUser mocks CreateUser of the AccountManager interface -func (am *MockAccountManager) CreateUser(accountID string, invite *server.UserInfo) (*server.UserInfo, error) { +func (am *MockAccountManager) CreateUser(accountID, userID string, invite *server.UserInfo) (*server.UserInfo, error) { if am.CreateUserFunc != nil { - return am.CreateUserFunc(accountID, invite) + return am.CreateUserFunc(accountID, userID, invite) } return nil, status.Errorf(codes.Unimplemented, "method CreateUser is not implemented") } @@ -477,7 +479,7 @@ func (am *MockAccountManager) GetPeers(accountID, userID string) ([]*server.Peer if am.GetAccountFromTokenFunc != nil { return am.GetPeersFunc(accountID, userID) } - return nil, status.Errorf(codes.Unimplemented, "method GetPeersFunc is not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetPeers is not implemented") } // GetDNSDomain mocks GetDNSDomain of the AccountManager interface @@ -487,3 +489,11 @@ func (am *MockAccountManager) GetDNSDomain() string { } return "" } + +// GetEvents mocks GetEvents of the AccountManager interface +func (am *MockAccountManager) GetEvents(accountID, userID string) ([]*activity.Event, error) { + if am.GetEventsFunc != nil { + return am.GetEventsFunc(accountID, userID) + } + return nil, status.Errorf(codes.Unimplemented, "method GetEvents is not implemented") +} diff --git a/management/server/user.go b/management/server/user.go index 17ba808a1..9e8a3fa59 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -2,10 +2,12 @@ package server import ( "fmt" + "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/netbird/management/server/jwtclaims" "github.com/netbirdio/netbird/management/server/status" "strings" + "time" ) const ( @@ -116,7 +118,7 @@ func NewAdminUser(id string) *User { } // CreateUser creates a new user under the given account. Effectively this is a user invite. -func (am *DefaultAccountManager) CreateUser(accountID string, invite *UserInfo) (*UserInfo, error) { +func (am *DefaultAccountManager) CreateUser(accountID, userID string, invite *UserInfo) (*UserInfo, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() @@ -175,6 +177,19 @@ func (am *DefaultAccountManager) CreateUser(accountID string, invite *UserInfo) return nil, err } + event := &activity.Event{ + Timestamp: time.Now(), + Activity: activity.UserInvited, + AccountID: account.Id, + TargetID: newUser.Id, + InitiatorID: userID, + } + + _, err = am.eventStore.Save(event) + if err != nil { + return nil, err + } + return newUser.toUserInfo(idpUser) }