From 5c19d9be7f20d4528331a0f9f6673d20bf16d57a Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Tue, 21 Feb 2017 21:07:57 +0900 Subject: Implement endpoint for APIv4: GET /users/{user_id}/audits (#5472) --- api4/user.go | 111 +++++++++++++++++++++++++----------------- api4/user_test.go | 27 +++++++++- app/audit.go | 10 +++- model/client4.go | 11 +++++ store/sql_audit_store.go | 6 +-- store/sql_audit_store_test.go | 9 ++-- store/store.go | 2 +- 7 files changed, 121 insertions(+), 55 deletions(-) diff --git a/api4/user.go b/api4/user.go index 5337cedf0..4c40ef4b4 100644 --- a/api4/user.go +++ b/api4/user.go @@ -36,6 +36,7 @@ func InitUser() { BaseRoutes.User.Handle("/sessions", ApiSessionRequired(getSessions)).Methods("GET") BaseRoutes.User.Handle("/sessions/revoke", ApiSessionRequired(revokeSession)).Methods("POST") + BaseRoutes.User.Handle("/audits", ApiSessionRequired(getAudits)).Methods("GET") } @@ -481,51 +482,71 @@ func Logout(c *Context, w http.ResponseWriter, r *http.Request) { } func getSessions(c *Context, w http.ResponseWriter, r *http.Request) { - c.RequireUserId() - if c.Err != nil { - return - } - - if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { - c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) - return - } - - if sessions, err := app.GetSessions(c.Params.UserId); err != nil { - c.Err = err - return - } else { - for _, session := range sessions { - session.Sanitize() - } - - w.Write([]byte(model.SessionsToJson(sessions))) - return - } + c.RequireUserId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { + c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + return + } + + if sessions, err := app.GetSessions(c.Params.UserId); err != nil { + c.Err = err + return + } else { + for _, session := range sessions { + session.Sanitize() + } + + w.Write([]byte(model.SessionsToJson(sessions))) + return + } } func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) { - c.RequireUserId() - if c.Err != nil { - return - } - - if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { - c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) - return - } - - props := model.MapFromJson(r.Body) - sessionId := props["session_id"] - - if sessionId == "" { - c.SetInvalidParam("session_id") - } - - if err := app.RevokeSessionById(sessionId); err != nil { - c.Err = err - return - } - - ReturnStatusOK(w) -} \ No newline at end of file + c.RequireUserId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { + c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + return + } + + props := model.MapFromJson(r.Body) + sessionId := props["session_id"] + + if sessionId == "" { + c.SetInvalidParam("session_id") + } + + if err := app.RevokeSessionById(sessionId); err != nil { + c.Err = err + return + } + + ReturnStatusOK(w) +} + +func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireUserId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { + c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + return + } + + if audits, err := app.GetAuditsPage(c.Params.UserId, c.Params.Page, c.Params.PerPage); err != nil { + c.Err = err + return + } else { + w.Write([]byte(audits.ToJson())) + return + } +} diff --git a/api4/user_test.go b/api4/user_test.go index 5fe497d90..07b9745c6 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -811,7 +811,7 @@ func TestGetSessions(t *testing.T) { user := th.BasicUser Client.Login(user.Email, user.Password) - + sessions, resp := Client.GetSessions(user.Id, "") for _, session := range sessions { if session.UserId != user.Id { @@ -899,3 +899,28 @@ func TestRevokeSessions(t *testing.T) { CheckNoError(t, resp) } + +func TestGetAudits(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + user := th.BasicUser + + audits, resp := Client.GetAudits(user.Id, 0, 100, "") + for _, audit := range audits { + if audit.UserId != user.Id { + t.Fatal("user id does not match audit user id") + } + } + CheckNoError(t, resp) + + _, resp = Client.GetAudits(th.BasicUser2.Id, 0, 100, "") + CheckForbiddenStatus(t, resp) + + Client.Logout() + _, resp = Client.GetAudits(user.Id, 0, 100, "") + CheckUnauthorizedStatus(t, resp) + + _, resp = th.SystemAdminClient.GetAudits(user.Id, 0, 100, "") + CheckNoError(t, resp) +} diff --git a/app/audit.go b/app/audit.go index 6978e9bc2..6b7439d43 100644 --- a/app/audit.go +++ b/app/audit.go @@ -8,7 +8,15 @@ import ( ) func GetAudits(userId string, limit int) (model.Audits, *model.AppError) { - if result := <-Srv.Store.Audit().Get(userId, limit); result.Err != nil { + if result := <-Srv.Store.Audit().Get(userId, 0, limit); result.Err != nil { + return nil, result.Err + } else { + return result.Data.(model.Audits), nil + } +} + +func GetAuditsPage(userId string, page int, perPage int) (model.Audits, *model.AppError) { + if result := <-Srv.Store.Audit().Get(userId, page*perPage, perPage); result.Err != nil { return nil, result.Err } else { return result.Data.(model.Audits), nil diff --git a/model/client4.go b/model/client4.go index f4447b769..8f9bb82f5 100644 --- a/model/client4.go +++ b/model/client4.go @@ -459,6 +459,17 @@ func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) { } } +// GetAudits returns a list of audit based on the provided user id string. +func (c *Client4) GetAudits(userId string, page int, perPage int, etag string) (Audits, *Response) { + query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) + if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return AuditsFromJson(r.Body), BuildResponse(r) + } +} + // Team Section // CreateTeam creates a team in the system based on the provided team struct. diff --git a/store/sql_audit_store.go b/store/sql_audit_store.go index 7e8fa74e4..693b46bb9 100644 --- a/store/sql_audit_store.go +++ b/store/sql_audit_store.go @@ -54,7 +54,7 @@ func (s SqlAuditStore) Save(audit *model.Audit) StoreChannel { return storeChannel } -func (s SqlAuditStore) Get(user_id string, limit int) StoreChannel { +func (s SqlAuditStore) Get(user_id string, offset int, limit int) StoreChannel { storeChannel := make(StoreChannel, 1) @@ -75,10 +75,10 @@ func (s SqlAuditStore) Get(user_id string, limit int) StoreChannel { query += " WHERE UserId = :user_id" } - query += " ORDER BY CreateAt DESC LIMIT :limit" + query += " ORDER BY CreateAt DESC LIMIT :limit OFFSET :offset" var audits model.Audits - if _, err := s.GetReplica().Select(&audits, query, map[string]interface{}{"user_id": user_id, "limit": limit}); err != nil { + if _, err := s.GetReplica().Select(&audits, query, map[string]interface{}{"user_id": user_id, "limit": limit, "offset": offset}); err != nil { result.Err = model.NewLocAppError("SqlAuditStore.Get", "store.sql_audit.get.finding.app_error", nil, "user_id="+user_id) } else { result.Data = audits diff --git a/store/sql_audit_store_test.go b/store/sql_audit_store_test.go index 841b79627..fcdada4e5 100644 --- a/store/sql_audit_store_test.go +++ b/store/sql_audit_store_test.go @@ -4,9 +4,10 @@ package store import ( - "github.com/mattermost/platform/model" "testing" "time" + + "github.com/mattermost/platform/model" ) func TestSqlAuditStore(t *testing.T) { @@ -25,7 +26,7 @@ func TestSqlAuditStore(t *testing.T) { time.Sleep(100 * time.Millisecond) - c := store.Audit().Get(audit.UserId, 100) + c := store.Audit().Get(audit.UserId, 0, 100) result := <-c audits := result.Data.(model.Audits) @@ -37,7 +38,7 @@ func TestSqlAuditStore(t *testing.T) { t.Fatal("Failed to save property for extra info") } - c = store.Audit().Get("missing", 100) + c = store.Audit().Get("missing", 0, 100) result = <-c audits = result.Data.(model.Audits) @@ -45,7 +46,7 @@ func TestSqlAuditStore(t *testing.T) { t.Fatal("Should have returned empty because user_id is missing") } - c = store.Audit().Get("", 100) + c = store.Audit().Get("", 0, 100) result = <-c audits = result.Data.(model.Audits) diff --git a/store/store.go b/store/store.go index 1a43767dd..6c78a235d 100644 --- a/store/store.go +++ b/store/store.go @@ -208,7 +208,7 @@ type SessionStore interface { type AuditStore interface { Save(audit *model.Audit) StoreChannel - Get(user_id string, limit int) StoreChannel + Get(user_id string, offset int, limit int) StoreChannel PermanentDeleteByUser(userId string) StoreChannel } -- cgit v1.2.3-1-g7c22