Bläddra i källkod

add user and network events api, add addtional events triggers

abhishek9686 4 månader sedan
förälder
incheckning
0f96bbbd7c

+ 52 - 0
controllers/acls.go

@@ -267,6 +267,22 @@ func createAcl(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Create,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   acl.ID,
+			Name: acl.Name,
+			Type: models.AclSub,
+		},
+		NetworkID: acl.NetworkID,
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(true)
 	logic.ReturnSuccessResponseWithJson(w, r, acl, "created acl successfully")
 }
@@ -309,6 +325,26 @@ func updateAcl(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Update,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   acl.ID,
+			Name: acl.Name,
+			Type: models.AclSub,
+		},
+		Diff: models.Diff{
+			Old: acl,
+			New: updateAcl.Acl,
+		},
+		NetworkID: acl.NetworkID,
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(true)
 	logic.ReturnSuccessResponse(w, r, "updated acl "+acl.Name)
 }
@@ -340,6 +376,22 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) {
 			logic.FormatError(errors.New("cannot delete default policy"), "internal"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Delete,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   acl.ID,
+			Name: acl.Name,
+			Type: models.AclSub,
+		},
+		NetworkID: acl.NetworkID,
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(true)
 	logic.ReturnSuccessResponse(w, r, "deleted acl "+acl.Name)
 }

+ 53 - 0
controllers/egress.go

@@ -85,6 +85,22 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
 		)
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Create,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   e.ID,
+			Name: e.Name,
+			Type: models.EgressSub,
+		},
+		NetworkID: models.NetworkID(e.Network),
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(false)
 	logic.ReturnSuccessResponseWithJson(w, r, e, "created egress resource")
 }
@@ -167,6 +183,25 @@ func updateEgress(w http.ResponseWriter, r *http.Request) {
 	if req.Status != e.Status {
 		updateStatus = true
 	}
+	event := &models.Event{
+		Action: models.Update,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   e.ID,
+			Name: e.Name,
+			Type: models.EgressSub,
+		},
+		Diff: models.Diff{
+			Old: e,
+		},
+		NetworkID: models.NetworkID(e.Network),
+		Origin:    models.Dashboard,
+	}
 	e.Nodes = make(datatypes.JSONMap)
 	e.Tags = make(datatypes.JSONMap)
 	for nodeID, metric := range req.Nodes {
@@ -201,6 +236,8 @@ func updateEgress(w http.ResponseWriter, r *http.Request) {
 		e.Status = req.Status
 		e.UpdateEgressStatus(db.WithContext(context.TODO()))
 	}
+	event.Diff.New = e
+	logic.LogEvent(event)
 	go mq.PublishPeerUpdate(false)
 	logic.ReturnSuccessResponseWithJson(w, r, e, "updated egress resource")
 }
@@ -227,6 +264,22 @@ func deleteEgress(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Delete,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   e.ID,
+			Name: e.Name,
+			Type: models.EgressSub,
+		},
+		NetworkID: models.NetworkID(e.Network),
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(false)
 	logic.ReturnSuccessResponseWithJson(w, r, nil, "deleted egress resource")
 }

+ 75 - 2
controllers/enrollmentkeys.go

@@ -72,12 +72,32 @@ func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) {
 func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 	params := mux.Vars(r)
 	keyID := params["keyID"]
-	err := logic.DeleteEnrollmentKey(keyID, false)
+	key, err := logic.GetEnrollmentKey(keyID)
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	err = logic.DeleteEnrollmentKey(keyID, false)
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to remove enrollment key: ", err.Error())
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Delete,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   keyID,
+			Name: key.Tags[0],
+			Type: models.EnrollmentKeySub,
+		},
+		Origin: models.Dashboard,
+	})
 	logger.Log(2, r.Header.Get("user"), "deleted enrollment key", keyID)
 	w.WriteHeader(http.StatusOK)
 }
@@ -173,6 +193,21 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
+	logic.LogEvent(&models.Event{
+		Action: models.Create,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   newEnrollmentKey.Value,
+			Name: newEnrollmentKey.Tags[0],
+			Type: models.EnrollmentKeySub,
+		},
+		Origin: models.Dashboard,
+	})
 	logger.Log(2, r.Header.Get("user"), "created enrollment key")
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newEnrollmentKey)
@@ -208,6 +243,7 @@ func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	currKey, _ := logic.GetEnrollmentKey(keyId)
 
 	newEnrollmentKey, err := logic.UpdateEnrollmentKey(keyId, relayId, enrollmentKeyBody.Groups)
 	if err != nil {
@@ -221,7 +257,25 @@ func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-
+	logic.LogEvent(&models.Event{
+		Action: models.Update,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   newEnrollmentKey.Value,
+			Name: newEnrollmentKey.Tags[0],
+			Type: models.EnrollmentKeySub,
+		},
+		Diff: models.Diff{
+			Old: currKey,
+			New: newEnrollmentKey,
+		},
+		Origin: models.Dashboard,
+	})
 	slog.Info("updated enrollment key", "id", keyId)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newEnrollmentKey)
@@ -355,6 +409,25 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) {
 		ServerConf:    server,
 		RequestedHost: newHost,
 	}
+	for _, netID := range enrollmentKey.Networks {
+		logic.LogEvent(&models.Event{
+			Action: models.JoinHostToNet,
+			Source: models.Subject{
+				ID:   enrollmentKey.Value,
+				Name: enrollmentKey.Tags[0],
+				Type: models.EnrollmentKeySub,
+			},
+			TriggeredBy: r.Header.Get("user"),
+			Target: models.Subject{
+				ID:   newHost.ID.String(),
+				Name: newHost.Name,
+				Type: models.DeviceSub,
+			},
+			NetworkID: models.NetworkID(netID),
+			Origin:    models.Dashboard,
+		})
+	}
+
 	logger.Log(0, newHost.Name, newHost.ID.String(), "registered with Netmaker")
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(&response)

+ 3 - 1
controllers/ext_client.go

@@ -806,12 +806,14 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 			Name: userName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: userName,
 		Target: models.Subject{
 			ID:   extclient.Network,
 			Name: extclient.Network,
 			Type: models.NetworkSub,
 		},
-		Origin: models.ClientApp,
+		NetworkID: models.NetworkID(extclient.Network),
+		Origin:    models.ClientApp,
 	})
 	w.WriteHeader(http.StatusOK)
 	go func() {

+ 32 - 0
controllers/hosts.go

@@ -492,6 +492,22 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
 		r.Header.Get("user"),
 		fmt.Sprintf("added host %s to network %s", currHost.Name, network),
 	)
+	logic.LogEvent(&models.Event{
+		Action: models.JoinHostToNet,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   currHost.ID.String(),
+			Name: currHost.Name,
+			Type: models.DeviceSub,
+		},
+		NetworkID: models.NetworkID(network),
+		Origin:    models.Dashboard,
+	})
 	w.WriteHeader(http.StatusOK)
 }
 
@@ -623,6 +639,22 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 			logic.SetDNS()
 		}
 	}()
+	logic.LogEvent(&models.Event{
+		Action: models.RemoveHostFromNet,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   currHost.ID.String(),
+			Name: currHost.Name,
+			Type: models.DeviceSub,
+		},
+		NetworkID: models.NetworkID(network),
+		Origin:    models.Dashboard,
+	})
 	logger.Log(
 		2,
 		r.Header.Get("user"),

+ 53 - 1
controllers/tags.go

@@ -131,6 +131,22 @@ func createTag(w http.ResponseWriter, r *http.Request) {
 			logic.UpsertNode(&node)
 		}
 	}()
+	logic.LogEvent(&models.Event{
+		Action: models.Create,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   tag.ID.String(),
+			Name: tag.TagName,
+			Type: models.TagSub,
+		},
+		NetworkID: tag.Network,
+		Origin:    models.Dashboard,
+	})
 	go mq.PublishPeerUpdate(false)
 
 	var res models.TagListRespNodes = models.TagListRespNodes{
@@ -163,6 +179,25 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
+	e := &models.Event{
+		Action: models.Update,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   tag.ID.String(),
+			Name: tag.TagName,
+			Type: models.TagSub,
+		},
+		Diff: models.Diff{
+			Old: tag,
+		},
+		NetworkID: tag.Network,
+		Origin:    models.Dashboard,
+	}
 	updateTag.NewName = strings.TrimSpace(updateTag.NewName)
 	var newID models.TagID
 	if updateTag.NewName != "" {
@@ -198,7 +233,8 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 		}
 		mq.PublishPeerUpdate(false)
 	}()
-
+	e.Diff.New = updateTag
+	logic.LogEvent(e)
 	var res models.TagListRespNodes = models.TagListRespNodes{
 		Tag:         tag,
 		UsedByCnt:   len(updateTag.TaggedNodes),
@@ -241,5 +277,21 @@ func deleteTag(w http.ResponseWriter, r *http.Request) {
 		logic.RemoveTagFromEnrollmentKeys(tag.ID)
 		mq.PublishPeerUpdate(false)
 	}()
+	logic.LogEvent(&models.Event{
+		Action: models.Delete,
+		Source: models.Subject{
+			ID:   r.Header.Get("user"),
+			Name: r.Header.Get("user"),
+			Type: models.UserSub,
+		},
+		TriggeredBy: r.Header.Get("user"),
+		Target: models.Subject{
+			ID:   tag.ID.String(),
+			Name: tag.TagName,
+			Type: models.TagSub,
+		},
+		NetworkID: tag.Network,
+		Origin:    models.Dashboard,
+	})
 	logic.ReturnSuccessResponse(w, r, "deleted tag "+tagID)
 }

+ 8 - 0
controllers/user.go

@@ -127,6 +127,7 @@ func createUserAccessToken(w http.ResponseWriter, r *http.Request) {
 			Name: caller.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: caller.UserName,
 		Target: models.Subject{
 			ID:   req.ID,
 			Name: req.Name,
@@ -220,6 +221,7 @@ func deleteUserAccessTokens(w http.ResponseWriter, r *http.Request) {
 			Name: caller.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: caller.UserName,
 		Target: models.Subject{
 			ID:   a.ID,
 			Name: a.Name,
@@ -297,6 +299,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 				Name: user.UserName,
 				Type: models.UserSub,
 			},
+			TriggeredBy: user.UserName,
 			Target: models.Subject{
 				ID:   models.DashboardSub.String(),
 				Name: models.DashboardSub.String(),
@@ -312,6 +315,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 				Name: user.UserName,
 				Type: models.UserSub,
 			},
+			TriggeredBy: user.UserName,
 			Target: models.Subject{
 				ID:   models.ClientAppSub.String(),
 				Name: models.ClientAppSub.String(),
@@ -682,6 +686,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 			Name: caller.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: caller.UserName,
 		Target: models.Subject{
 			ID:   user.UserName,
 			Name: user.UserName,
@@ -834,6 +839,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 			Name: caller.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: caller.UserName,
 		Target: models.Subject{
 			ID:   user.UserName,
 			Name: user.UserName,
@@ -938,6 +944,7 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 			Name: caller.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: caller.UserName,
 		Target: models.Subject{
 			ID:   user.UserName,
 			Name: user.UserName,
@@ -1045,6 +1052,7 @@ func logout(w http.ResponseWriter, r *http.Request) {
 				Name: user.UserName,
 				Type: models.UserSub,
 			},
+			TriggeredBy: user.UserName,
 			Target: models.Subject{
 				ID:   target.String(),
 				Name: target.String(),

+ 3 - 1
logic/extpeers.go

@@ -127,12 +127,14 @@ func DeleteExtClient(network string, clientid string) error {
 				Name: extClient.OwnerID,
 				Type: models.UserSub,
 			},
+			TriggeredBy: extClient.OwnerID,
 			Target: models.Subject{
 				ID:   extClient.Network,
 				Name: extClient.Network,
 				Type: models.NetworkSub,
 			},
-			Origin: models.ClientApp,
+			NetworkID: models.NetworkID(extClient.Network),
+			Origin:    models.ClientApp,
 		})
 	}
 	go RemoveNodeFromAclPolicy(extClient.ConvertToStaticNode())

+ 20 - 15
models/events.go

@@ -3,14 +3,16 @@ package models
 type Action string
 
 const (
-	Create     Action = "CREATE"
-	Update     Action = "UPDATE"
-	Delete     Action = "DELETE"
-	DeleteAll  Action = "DELETE_ALL"
-	Login      Action = "LOGIN"
-	LogOut     Action = "LOGOUT"
-	Connect    Action = "CONNECT"
-	Disconnect Action = "DISCONNECT"
+	Create            Action = "CREATE"
+	Update            Action = "UPDATE"
+	Delete            Action = "DELETE"
+	DeleteAll         Action = "DELETE_ALL"
+	Login             Action = "LOGIN"
+	LogOut            Action = "LOGOUT"
+	Connect           Action = "CONNECT"
+	Disconnect        Action = "DISCONNECT"
+	JoinHostToNet     Action = "JOIN_HOST_TO_NETWORK"
+	RemoveHostFromNet Action = "REMOVE_HOST_FROM_NETWORK"
 )
 
 type SubjectType string
@@ -21,7 +23,8 @@ const (
 	DeviceSub          SubjectType = "DEVICE"
 	NodeSub            SubjectType = "NODE"
 	SettingSub         SubjectType = "SETTING"
-	AclSub             SubjectType = "ACLs"
+	AclSub             SubjectType = "ACL"
+	TagSub             SubjectType = "TAG"
 	UserRoleSub        SubjectType = "USER_ROLE"
 	UserGroupSub       SubjectType = "USER_GROUP"
 	UserInviteSub      SubjectType = "USER_INVITE"
@@ -29,6 +32,7 @@ const (
 	EgressSub          SubjectType = "EGRESS"
 	NetworkSub         SubjectType = "NETWORK"
 	DashboardSub       SubjectType = "DASHBOARD"
+	EnrollmentKeySub   SubjectType = "ENROLLMENT_KEY"
 	ClientAppSub       SubjectType = "CLIENT-APP"
 )
 
@@ -58,10 +62,11 @@ type Diff struct {
 }
 
 type Event struct {
-	Action    Action
-	Source    Subject
-	Origin    Origin
-	Target    Subject
-	NetworkID NetworkID
-	Diff      Diff
+	Action      Action
+	Source      Subject
+	Origin      Origin
+	Target      Subject
+	TriggeredBy string
+	NetworkID   NetworkID
+	Diff        Diff
 }

+ 1 - 0
pro/auth/azure-ad.go

@@ -183,6 +183,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
 			Name: user.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: user.UserName,
 		Target: models.Subject{
 			ID:   models.DashboardSub.String(),
 			Name: models.DashboardSub.String(),

+ 1 - 0
pro/auth/github.go

@@ -174,6 +174,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
 			Name: user.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: user.UserName,
 		Target: models.Subject{
 			ID:   models.DashboardSub.String(),
 			Name: models.DashboardSub.String(),

+ 1 - 0
pro/auth/google.go

@@ -168,6 +168,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
 			Name: user.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: user.UserName,
 		Target: models.Subject{
 			ID:   models.DashboardSub.String(),
 			Name: models.DashboardSub.String(),

+ 1 - 0
pro/auth/oidc.go

@@ -174,6 +174,7 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
 			Name: user.UserName,
 			Type: models.UserSub,
 		},
+		TriggeredBy: user.UserName,
 		Target: models.Subject{
 			ID:   models.DashboardSub.String(),
 			Name: models.DashboardSub.String(),

+ 64 - 3
pro/controllers/events.go

@@ -12,22 +12,31 @@ import (
 )
 
 func EventHandlers(r *mux.Router) {
+	r.HandleFunc("/api/v1/network/activity", logic.SecurityCheck(true, http.HandlerFunc(listNetworkActivity))).Methods(http.MethodGet)
+	r.HandleFunc("/api/v1/user/activity", logic.SecurityCheck(true, http.HandlerFunc(listUserActivity))).Methods(http.MethodGet)
 	r.HandleFunc("/api/v1/activity", logic.SecurityCheck(true, http.HandlerFunc(listActivity))).Methods(http.MethodGet)
 }
 
 // @Summary     list activity.
 // @Router      /api/v1/activity [get]
 // @Tags        Activity
-// @Param       network_id query string true "roleid required to get the role details"
+// @Param       network_id query string true "network_id required to get the network events"
 // @Success     200 {object}  models.ReturnSuccessResponseWithJson
 // @Failure     500 {object} models.ErrorResponse
-func listActivity(w http.ResponseWriter, r *http.Request) {
+func listNetworkActivity(w http.ResponseWriter, r *http.Request) {
 	netID := r.URL.Query().Get("network_id")
 	// Parse query parameters with defaults
+	if netID == "" {
+		logic.ReturnErrorResponse(w, r, models.ErrorResponse{
+			Code:    http.StatusBadRequest,
+			Message: "network_id param is missing",
+		})
+		return
+	}
 	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
 	pageSize, _ := strconv.Atoi(r.URL.Query().Get("per_page"))
 	ctx := db.WithContext(r.Context())
-	netActivity, err := (&schema.Event{NetworkID: models.NetworkID(netID)}).List(db.SetPagination(ctx, page, pageSize))
+	netActivity, err := (&schema.Event{NetworkID: models.NetworkID(netID)}).ListByNetwork(db.SetPagination(ctx, page, pageSize))
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, models.ErrorResponse{
 			Code:    http.StatusInternalServerError,
@@ -38,3 +47,55 @@ func listActivity(w http.ResponseWriter, r *http.Request) {
 
 	logic.ReturnSuccessResponseWithJson(w, r, netActivity, "successfully fetched network activity")
 }
+
+// @Summary     list activity.
+// @Router      /api/v1/activity [get]
+// @Tags        Activity
+// @Param       network_id query string true "network_id required to get the network events"
+// @Success     200 {object}  models.ReturnSuccessResponseWithJson
+// @Failure     500 {object} models.ErrorResponse
+func listUserActivity(w http.ResponseWriter, r *http.Request) {
+	username := r.URL.Query().Get("username")
+	// Parse query parameters with defaults
+	if username == "" {
+		logic.ReturnErrorResponse(w, r, models.ErrorResponse{
+			Code:    http.StatusBadRequest,
+			Message: "username param is missing",
+		})
+		return
+	}
+	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
+	pageSize, _ := strconv.Atoi(r.URL.Query().Get("per_page"))
+	ctx := db.WithContext(r.Context())
+	userActivity, err := (&schema.Event{TriggeredBy: username}).ListByUser(db.SetPagination(ctx, page, pageSize))
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, models.ErrorResponse{
+			Code:    http.StatusInternalServerError,
+			Message: err.Error(),
+		})
+		return
+	}
+
+	logic.ReturnSuccessResponseWithJson(w, r, userActivity, "successfully fetched user activity "+username)
+}
+
+// @Summary     list activity.
+// @Router      /api/v1/activity [get]
+// @Tags        Activity
+// @Success     200 {object}  models.ReturnSuccessResponseWithJson
+// @Failure     500 {object} models.ErrorResponse
+func listActivity(w http.ResponseWriter, r *http.Request) {
+	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
+	pageSize, _ := strconv.Atoi(r.URL.Query().Get("per_page"))
+	ctx := db.WithContext(r.Context())
+	events, err := (&schema.Event{}).List(db.SetPagination(ctx, page, pageSize))
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, models.ErrorResponse{
+			Code:    http.StatusInternalServerError,
+			Message: err.Error(),
+		})
+		return
+	}
+
+	logic.ReturnSuccessResponseWithJson(w, r, events, "successfully fetched all events ")
+}

+ 13 - 2
pro/controllers/users.go

@@ -250,10 +250,11 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
 		logic.LogEvent(&models.Event{
 			Action: models.Create,
 			Source: models.Subject{
-				ID:   r.Header.Get("user"),
-				Name: r.Header.Get("user"),
+				ID:   callerUserName,
+				Name: callerUserName,
 				Type: models.UserSub,
 			},
+			TriggeredBy: callerUserName,
 			Target: models.Subject{
 				ID:   inviteeEmail,
 				Name: inviteeEmail,
@@ -330,6 +331,7 @@ func deleteUserInvite(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   email,
 			Name: email,
@@ -498,6 +500,7 @@ func createUserGroup(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   userGroupReq.Group.ID.String(),
 			Name: userGroupReq.Group.Name,
@@ -555,6 +558,7 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   userGroup.ID.String(),
 			Name: userGroup.Name,
@@ -617,6 +621,7 @@ func deleteUserGroup(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   userG.ID.String(),
 			Name: userG.Name,
@@ -711,6 +716,7 @@ func createRole(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   userRole.ID.String(),
 			Name: userRole.Name,
@@ -759,6 +765,7 @@ func updateRole(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   userRole.ID.String(),
 			Name: userRole.Name,
@@ -805,6 +812,7 @@ func deleteRole(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   role.ID.String(),
 			Name: role.Name,
@@ -1475,6 +1483,7 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   username,
 			Name: username,
@@ -1520,6 +1529,7 @@ func deletePendingUser(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   username,
 			Name: username,
@@ -1549,6 +1559,7 @@ func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
 			Name: r.Header.Get("user"),
 			Type: models.UserSub,
 		},
+		TriggeredBy: r.Header.Get("user"),
 		Target: models.Subject{
 			ID:   r.Header.Get("user"),
 			Name: r.Header.Get("user"),

+ 8 - 7
pro/logic/events.go

@@ -23,13 +23,14 @@ func EventWatcher() {
 		sourceJson, _ := json.Marshal(e.Source)
 		dstJson, _ := json.Marshal(e.Target)
 		a := schema.Event{
-			ID:        uuid.New().String(),
-			Action:    e.Action,
-			Source:    sourceJson,
-			Target:    dstJson,
-			Origin:    e.Origin,
-			NetworkID: e.NetworkID,
-			TimeStamp: time.Now().UTC(),
+			ID:          uuid.New().String(),
+			Action:      e.Action,
+			Source:      sourceJson,
+			Target:      dstJson,
+			Origin:      e.Origin,
+			NetworkID:   e.NetworkID,
+			TriggeredBy: e.TriggeredBy,
+			TimeStamp:   time.Now().UTC(),
 		}
 		a.Create(db.WithContext(context.TODO()))
 	}

+ 18 - 7
schema/event.go

@@ -10,13 +10,14 @@ import (
 )
 
 type Event struct {
-	ID        string           `gorm:"primaryKey" json:"id"`
-	Action    models.Action    `gorm:"action" json:"action"`
-	Source    datatypes.JSON   `gorm:"source" json:"source"`
-	Origin    models.Origin    `gorm:"origin" json:"origin"`
-	Target    datatypes.JSON   `gorm:"target" json:"target"`
-	NetworkID models.NetworkID `gorm:"network_id" json:"network_id"`
-	TimeStamp time.Time        `gorm:"time_stamp" json:"time_stamp"`
+	ID          string           `gorm:"primaryKey" json:"id"`
+	Action      models.Action    `gorm:"action" json:"action"`
+	Source      datatypes.JSON   `gorm:"source" json:"source"`
+	Origin      models.Origin    `gorm:"origin" json:"origin"`
+	Target      datatypes.JSON   `gorm:"target" json:"target"`
+	NetworkID   models.NetworkID `gorm:"network_id" json:"network_id"`
+	TriggeredBy string           `gorm:"triggered_by" json:"triggered_by"`
+	TimeStamp   time.Time        `gorm:"time_stamp" json:"time_stamp"`
 }
 
 func (a *Event) Get(ctx context.Context) error {
@@ -31,6 +32,16 @@ func (a *Event) Create(ctx context.Context) error {
 	return db.FromContext(ctx).Model(&Event{}).Create(&a).Error
 }
 
+func (a *Event) ListByNetwork(ctx context.Context) (ats []Event, err error) {
+	err = db.FromContext(ctx).Model(&Event{}).Where("network_id = ?", a.NetworkID).Order("time_stamp DESC").Find(&ats).Error
+	return
+}
+
+func (a *Event) ListByUser(ctx context.Context) (ats []Event, err error) {
+	err = db.FromContext(ctx).Model(&Event{}).Where("triggered_by = ?", a.TriggeredBy).Order("time_stamp DESC").Find(&ats).Error
+	return
+}
+
 func (a *Event) List(ctx context.Context) (ats []Event, err error) {
 	err = db.FromContext(ctx).Model(&Event{}).Order("time_stamp DESC").Find(&ats).Error
 	return