diff --git a/api/activity.go b/api/activity.go index ed80496b2..62a4ef267 100644 --- a/api/activity.go +++ b/api/activity.go @@ -1,5 +1,7 @@ package api +import "github.com/usememos/memos/server/profile" + // ActivityType is the type for an activity. type ActivityType string @@ -16,8 +18,6 @@ const ( ActivityUserAuthSignIn ActivityType = "user.auth.signin" // ActivityUserAuthSignUp is the type for user signup. ActivityUserAuthSignUp ActivityType = "user.auth.signup" - // ActivityUserAuthSignOut is the type for user signout. - ActivityUserAuthSignOut ActivityType = "user.auth.signout" // ActivityUserSettingUpdate is the type for updating user settings. ActivityUserSettingUpdate ActivityType = "user.setting.update" @@ -39,6 +39,13 @@ const ( // ActivityShortcutDelete is the type for deleting shortcuts. ActivityShortcutDelete ActivityType = "shortcut.delete" + // Resource related. + + // ActivityResourceCreate is the type for creating resources. + ActivityResourceCreate ActivityType = "resource.create" + // ActivityResourceDelete is the type for deleting resources. + ActivityResourceDelete ActivityType = "resource.delete" + // Tag related. // ActivityTagCreate is the type for creating tags. @@ -64,11 +71,41 @@ const ( ActivityError ActivityLevel = "ERROR" ) +type ActivityUserCreatePayload struct { + UserID int `json:"userId"` + Username string `json:"username"` + Role Role `json:"role"` +} + type ActivityUserAuthSignInPayload struct { UserID int `json:"userId"` IP string `json:"ip"` } +type ActivityUserAuthSignUpPayload struct { + Username string `json:"username"` + IP string `json:"ip"` +} + +type ActivityShortcutCreatePayload struct { + Title string `json:"title"` + Payload string `json:"payload"` +} + +type ActivityResourceCreatePayload struct { + Filename string `json:"filename"` + Type string `json:"type"` + Size int64 `json:"size"` +} + +type ActivityTagCreatePayload struct { + TagName string `json:"tagName"` +} + +type ActivityServerStartPayload struct { + Profile *profile.Profile `json:"profile"` +} + type Activity struct { ID int `json:"id"` diff --git a/bin/server/main.go b/bin/server/main.go index 5157fc3a2..edd86b4dd 100644 --- a/bin/server/main.go +++ b/bin/server/main.go @@ -8,7 +8,6 @@ import ( "context" "fmt" - metric "github.com/usememos/memos/plugin/metrics" "github.com/usememos/memos/server" "github.com/usememos/memos/server/profile" "github.com/usememos/memos/store" @@ -46,11 +45,7 @@ func run(profile *profile.Profile) error { println(greetingBanner) fmt.Printf("Version %s has started at :%d\n", profile.Version, profile.Port) - metricCollector.Collect(ctx, &metric.Metric{ - Name: "service started", - }) - - return serverInstance.Run() + return serverInstance.Run(ctx) } func execute() error { diff --git a/server/auth.go b/server/auth.go index e12fbd710..33aec950c 100644 --- a/server/auth.go +++ b/server/auth.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" @@ -115,9 +114,9 @@ func (s *Server) registerAuthRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "user signed up", - }) + if err := s.createUserAuthSignUpActivity(c, user); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) + } err = setUserSession(c, user) if err != nil { @@ -132,14 +131,10 @@ func (s *Server) registerAuthRoutes(g *echo.Group) { }) g.POST("/auth/signout", func(c echo.Context) error { - ctx := c.Request().Context() err := removeUserSession(c) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to set sign out session").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "user signout", - }) return c.JSON(http.StatusOK, true) }) @@ -153,7 +148,7 @@ func (s *Server) createUserAuthSignInActivity(c echo.Context, user *api.User) er } payloadStr, err := json.Marshal(payload) if err != nil { - return errors.Wrap(err, "failed to malshal activity payload") + return errors.Wrap(err, "failed to marshal activity payload") } _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ CreatorID: user.ID, @@ -163,3 +158,22 @@ func (s *Server) createUserAuthSignInActivity(c echo.Context, user *api.User) er }) return err } + +func (s *Server) createUserAuthSignUpActivity(c echo.Context, user *api.User) error { + ctx := c.Request().Context() + payload := api.ActivityUserAuthSignUpPayload{ + Username: user.Username, + IP: echo.ExtractIPFromRealIPHeader()(c.Request()), + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: user.ID, + Type: api.ActivityUserAuthSignUp, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +} diff --git a/server/http_getter.go b/server/http_getter.go index a0c40ada9..de75566ed 100644 --- a/server/http_getter.go +++ b/server/http_getter.go @@ -8,12 +8,10 @@ import ( "github.com/labstack/echo/v4" getter "github.com/usememos/memos/plugin/http_getter" - metric "github.com/usememos/memos/plugin/metrics" ) -func (s *Server) registerGetterPublicRoutes(g *echo.Group) { +func registerGetterPublicRoutes(g *echo.Group) { g.GET("/get/httpmeta", func(c echo.Context) error { - ctx := c.Request().Context() urlStr := c.QueryParam("url") if urlStr == "" { return echo.NewHTTPError(http.StatusBadRequest, "Missing website url") @@ -26,12 +24,6 @@ func (s *Server) registerGetterPublicRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusNotAcceptable, fmt.Sprintf("Failed to get website meta with url: %s", urlStr)).SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "getter used", - Labels: map[string]string{ - "type": "httpmeta", - }, - }) c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(htmlMeta)); err != nil { @@ -41,7 +33,6 @@ func (s *Server) registerGetterPublicRoutes(g *echo.Group) { }) g.GET("/get/image", func(c echo.Context) error { - ctx := c.Request().Context() urlStr := c.QueryParam("url") if urlStr == "" { return echo.NewHTTPError(http.StatusBadRequest, "Missing image url") @@ -54,12 +45,6 @@ func (s *Server) registerGetterPublicRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Failed to get image url: %s", urlStr)).SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "getter used", - Labels: map[string]string{ - "type": "image", - }, - }) c.Response().Writer.WriteHeader(http.StatusOK) c.Response().Writer.Header().Set("Content-Type", image.Mediatype) diff --git a/server/resource.go b/server/resource.go index 09e312452..684ae17dd 100644 --- a/server/resource.go +++ b/server/resource.go @@ -9,9 +9,9 @@ import ( "strconv" "time" + "github.com/pkg/errors" "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" ) @@ -66,9 +66,9 @@ func (s *Server) registerResourceRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create resource").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "resource created", - }) + if err := s.createResourceCreateActivity(c, resource); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) + } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(resource)); err != nil { @@ -275,3 +275,23 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) { return nil }) } + +func (s *Server) createResourceCreateActivity(c echo.Context, resource *api.Resource) error { + ctx := c.Request().Context() + payload := api.ActivityResourceCreatePayload{ + Filename: resource.Filename, + Type: resource.Type, + Size: resource.Size, + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: resource.CreatorID, + Type: api.ActivityResourceCreate, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +} diff --git a/server/server.go b/server/server.go index 322063c5c..5c50f5e1c 100644 --- a/server/server.go +++ b/server/server.go @@ -1,9 +1,13 @@ package server import ( + "context" + "encoding/json" "fmt" "time" + "github.com/pkg/errors" + "github.com/usememos/memos/api" "github.com/usememos/memos/server/profile" "github.com/usememos/memos/store" @@ -77,7 +81,7 @@ func NewServer(profile *profile.Profile) *Server { publicGroup := e.Group("/o") s.registerResourcePublicRoutes(publicGroup) - s.registerGetterPublicRoutes(publicGroup) + registerGetterPublicRoutes(publicGroup) apiGroup := e.Group("/api") apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc { @@ -94,6 +98,26 @@ func NewServer(profile *profile.Profile) *Server { return s } -func (s *Server) Run() error { +func (s *Server) Run(ctx context.Context) error { + if err := s.createServerStartActivity(ctx); err != nil { + return errors.Wrap(err, "failed to create activity") + } return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port)) } + +func (s *Server) createServerStartActivity(ctx context.Context) error { + payload := api.ActivityServerStartPayload{ + Profile: s.Profile, + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: api.UnknownID, + Type: api.ActivityServerStart, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +} diff --git a/server/shortcut.go b/server/shortcut.go index 4f78032ab..73705886a 100644 --- a/server/shortcut.go +++ b/server/shortcut.go @@ -7,9 +7,9 @@ import ( "strconv" "time" + "github.com/pkg/errors" "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" ) @@ -31,9 +31,9 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create shortcut").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "shortcut created", - }) + if err := s.createShortcutCreateActivity(c, shortcut); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) + } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(shortcut)); err != nil { @@ -164,3 +164,22 @@ func (s *Server) registerShortcutRoutes(g *echo.Group) { return c.JSON(http.StatusOK, true) }) } + +func (s *Server) createShortcutCreateActivity(c echo.Context, shortcut *api.Shortcut) error { + ctx := c.Request().Context() + payload := api.ActivityShortcutCreatePayload{ + Title: shortcut.Title, + Payload: shortcut.Payload, + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: shortcut.CreatorID, + Type: api.ActivityShortcutCreate, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +} diff --git a/server/system.go b/server/system.go index 74a37685c..cc75c3a0b 100644 --- a/server/system.go +++ b/server/system.go @@ -7,7 +7,6 @@ import ( "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" ) @@ -152,10 +151,6 @@ func (s *Server) registerSystemRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert system setting").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "systemSetting updated", - Labels: map[string]string{"field": string(systemSettingUpsert.Name)}, - }) c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(systemSetting)); err != nil { diff --git a/server/tag.go b/server/tag.go index d1ef45d91..f01ebe7a6 100644 --- a/server/tag.go +++ b/server/tag.go @@ -7,9 +7,9 @@ import ( "regexp" "sort" + "github.com/pkg/errors" "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" ) @@ -35,9 +35,9 @@ func (s *Server) registerTagRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert tag").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "tag created", - }) + if err := s.createTagCreateActivity(c, tag); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) + } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(tag.Name)); err != nil { @@ -155,3 +155,21 @@ func findTagListFromMemoContent(memoContent string) []string { sort.Strings(tagList) return tagList } + +func (s *Server) createTagCreateActivity(c echo.Context, tag *api.Tag) error { + ctx := c.Request().Context() + payload := api.ActivityTagCreatePayload{ + TagName: tag.Name, + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: tag.CreatorID, + Type: api.ActivityTagCreate, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +} diff --git a/server/user.go b/server/user.go index 8b608b8bb..625703eee 100644 --- a/server/user.go +++ b/server/user.go @@ -7,9 +7,9 @@ import ( "strconv" "time" + "github.com/pkg/errors" "github.com/usememos/memos/api" "github.com/usememos/memos/common" - metric "github.com/usememos/memos/plugin/metrics" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" @@ -55,9 +55,9 @@ func (s *Server) registerUserRoutes(g *echo.Group) { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err) } - s.Collector.Collect(ctx, &metric.Metric{ - Name: "user created", - }) + if err := s.createUserCreateActivity(c, user); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) + } c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(user)); err != nil { @@ -277,3 +277,23 @@ func (s *Server) registerUserRoutes(g *echo.Group) { return c.JSON(http.StatusOK, true) }) } + +func (s *Server) createUserCreateActivity(c echo.Context, user *api.User) error { + ctx := c.Request().Context() + payload := api.ActivityUserCreatePayload{ + UserID: user.ID, + Username: user.Username, + Role: user.Role, + } + payloadStr, err := json.Marshal(payload) + if err != nil { + return errors.Wrap(err, "failed to marshal activity payload") + } + _, err = s.Store.CreateActivity(ctx, &api.ActivityCreate{ + CreatorID: user.ID, + Type: api.ActivityUserCreate, + Level: api.ActivityInfo, + Payload: string(payloadStr), + }) + return err +}