New report router and user reporting refactoring (#25713)

* Added materialized view migration

* Renamed mat view

* Added channel membership mat view and indexes

* Added channel membership mat view and indexes

* Added new index

* WIP

* Simplifying user reporting code

* Created app and API layer for cahnnel reporting, reporting refactoring in general

* New router

* Remobved channel reporting meanwhile

* Upodated autogenerated stuff

* Lint fix

* Fixed typo

* api vet

* i18n fix

* Fixed API vetting and removed channel reporting constants

* yaml

* removed app pagination tests
Этот коммит содержится в:
Harshil Sharma
2023-12-14 21:19:19 +05:30
коммит произвёл GitHub
родитель 32880efa25
Коммит 97a23d791e
16 изменённых файлов: 380 добавлений и 1339 удалений

Просмотреть файл

@@ -139,6 +139,8 @@ type Routes struct {
Drafts *mux.Router // 'api/v4/drafts'
IPFiltering *mux.Router // 'api/v4/ip_filtering'
Reports *mux.Router // 'api/v4/reports'
}
type API struct {
@@ -265,6 +267,8 @@ func Init(srv *app.Server) (*API, error) {
api.BaseRoutes.IPFiltering = api.BaseRoutes.APIRoot.PathPrefix("/ip_filtering").Subrouter()
api.BaseRoutes.Reports = api.BaseRoutes.APIRoot.PathPrefix("/reports").Subrouter()
api.InitUser()
api.InitBot()
api.InitTeam()
@@ -309,6 +313,7 @@ func Init(srv *app.Server) (*API, error) {
api.InitHostedCustomer()
api.InitDrafts()
api.InitIPFiltering()
api.InitReports()
srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))

81
server/channels/api4/report.go Обычный файл
Просмотреть файл

@@ -0,0 +1,81 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"encoding/json"
"net/http"
"strconv"
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/mlog"
)
func (api *API) InitReports() {
api.BaseRoutes.Reports.Handle("/users", api.APISessionRequired(getUsersForReporting)).Methods("GET")
}
func getUsersForReporting(c *Context, w http.ResponseWriter, r *http.Request) {
if !(c.IsSystemAdmin() && c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadUserManagementUsers)) {
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementUsers)
return
}
sortColumn := "Username"
if r.URL.Query().Get("sort_column") != "" {
sortColumn = r.URL.Query().Get("sort_column")
}
pageSize := 50
if pageSizeStr, err := strconv.ParseInt(r.URL.Query().Get("page_size"), 10, 64); err == nil {
pageSize = int(pageSizeStr)
}
teamFilter := r.URL.Query().Get("team_filter")
if !(teamFilter == "" || model.IsValidId(teamFilter)) {
c.Err = model.NewAppError("getUsersForReporting", "api.getUsersForReporting.invalid_team_filter", nil, "", http.StatusBadRequest)
return
}
hideActive := r.URL.Query().Get("hide_active") == "true"
hideInactive := r.URL.Query().Get("hide_inactive") == "true"
if hideActive && hideInactive {
c.Err = model.NewAppError("getUsersForReporting", "api.getUsersForReporting.invalid_active_filter", nil, "", http.StatusBadRequest)
return
}
options := &model.UserReportOptions{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: sortColumn,
SortDesc: r.URL.Query().Get("sort_direction") == "desc",
PageSize: pageSize,
LastSortColumnValue: r.URL.Query().Get("last_column_value"),
DateRange: r.URL.Query().Get("date_range"),
},
Team: teamFilter,
LastUserId: r.URL.Query().Get("last_id"),
Role: r.URL.Query().Get("role_filter"),
HasNoTeam: r.URL.Query().Get("has_no_team") == "true",
HideActive: hideActive,
HideInactive: hideInactive,
}
options.PopulateDateRange(time.Now())
// Don't allow fetching more than 100 users at a time from the normal query endpoint
if options.PageSize <= 0 || options.PageSize > model.ReportingMaxPageSize {
c.Err = model.NewAppError("getUsersForReporting", "api.getUsersForReporting.invalid_page_size", nil, "", http.StatusBadRequest)
return
}
userReports, err := c.App.GetUsersForReporting(options)
if err != nil {
c.Err = err
return
}
if jsonErr := json.NewEncoder(w).Encode(userReports); jsonErr != nil {
c.Logger.Warn("Error writing response", mlog.Err(jsonErr))
}
}

Просмотреть файл

@@ -108,8 +108,6 @@ func (api *API) InitUser() {
api.BaseRoutes.Users.Handle("/notify-admin", api.APISessionRequired(handleNotifyAdmin)).Methods("POST")
api.BaseRoutes.Users.Handle("/trigger-notify-admin-posts", api.APISessionRequired(handleTriggerNotifyAdminPosts)).Methods("POST")
api.BaseRoutes.Users.Handle("/report", api.APISessionRequired(getUsersForReporting)).Methods("GET")
}
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -3445,59 +3443,3 @@ func getUsersWithInvalidEmails(c *Context, w http.ResponseWriter, r *http.Reques
c.Logger.Warn("Error writing response", mlog.Err(err))
}
}
func getUsersForReporting(c *Context, w http.ResponseWriter, r *http.Request) {
if !(c.IsSystemAdmin() && c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadUserManagementUsers)) {
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementUsers)
return
}
sortColumn := "Username"
if r.URL.Query().Get("sort_column") != "" {
sortColumn = r.URL.Query().Get("sort_column")
}
pageSize := 50
if pageSizeStr, err := strconv.ParseInt(r.URL.Query().Get("page_size"), 10, 64); err == nil {
pageSize = int(pageSizeStr)
}
teamFilter := r.URL.Query().Get("team_filter")
if !(teamFilter == "" || model.IsValidId(teamFilter)) {
c.Err = model.NewAppError("getUsersForReporting", "api.getUsersForReporting.invalid_team_filter", nil, "", http.StatusBadRequest)
return
}
hideActive := r.URL.Query().Get("hide_active") == "true"
hideInactive := r.URL.Query().Get("hide_inactive") == "true"
if hideActive && hideInactive {
c.Err = model.NewAppError("getUsersForReporting", "api.getUsersForReporting.invalid_active_filter", nil, "", http.StatusBadRequest)
return
}
options := &model.UserReportOptionsAPI{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
SortColumn: sortColumn,
SortDesc: r.URL.Query().Get("sort_direction") == "desc",
PageSize: pageSize,
Team: teamFilter,
LastSortColumnValue: r.URL.Query().Get("last_column_value"),
LastUserId: r.URL.Query().Get("last_id"),
Role: r.URL.Query().Get("role_filter"),
HasNoTeam: r.URL.Query().Get("has_no_team") == "true",
HideActive: hideActive,
HideInactive: hideInactive,
},
DateRange: r.URL.Query().Get("date_range"),
}
userReports, err := c.App.GetUsersForReporting(options.ToBaseOptions(time.Now()))
if err != nil {
c.Err = err
return
}
if jsonErr := json.NewEncoder(w).Encode(userReports); jsonErr != nil {
c.Logger.Warn("Error writing response", mlog.Err(jsonErr))
}
}

32
server/channels/app/report.go Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"net/http"
"github.com/mattermost/mattermost/server/public/model"
)
func (a *App) GetUsersForReporting(filter *model.UserReportOptions) ([]*model.UserReport, *model.AppError) {
if appErr := filter.IsValid(); appErr != nil {
return nil, appErr
}
return a.getUserReport(filter)
}
func (a *App) getUserReport(filter *model.UserReportOptions) ([]*model.UserReport, *model.AppError) {
userReportQuery, err := a.Srv().Store().User().GetUserReport(filter)
if err != nil {
return nil, model.NewAppError("GetUsersForReporting", "app.report.get_user_report.store_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
userReports := make([]*model.UserReport, len(userReportQuery))
for i, user := range userReportQuery {
userReports[i] = user.ToReport()
}
return userReports, nil
}

Просмотреть файл

@@ -24,7 +24,6 @@ import (
"github.com/mattermost/mattermost/server/public/shared/i18n"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/public/shared/request"
pUtils "github.com/mattermost/mattermost/server/public/utils"
"github.com/mattermost/mattermost/server/v8/channels/app/email"
"github.com/mattermost/mattermost/server/v8/channels/app/imaging"
"github.com/mattermost/mattermost/server/v8/channels/app/users"
@@ -2818,36 +2817,3 @@ func (a *App) UserIsFirstAdmin(user *model.User) bool {
return true
}
func (a *App) GetUsersForReporting(filter *model.UserReportOptions) ([]*model.UserReport, *model.AppError) {
// Don't allow fetching more than 100 users at a time from the normal query endpoint
if filter.PageSize <= 0 || filter.PageSize > 100 {
return nil, model.NewAppError("GetUsersForReporting", "app.user.get_users_for_reporting.invalid_page_size", nil, "", http.StatusBadRequest)
}
// Validate date range
if filter.EndAt > 0 && filter.StartAt > filter.EndAt {
return nil, model.NewAppError("GetUsersForReporting", "app.user.get_users_for_reporting.bad_date_range", nil, "", http.StatusBadRequest)
}
return a.getUserReport(filter)
}
func (a *App) getUserReport(filter *model.UserReportOptions) ([]*model.UserReport, *model.AppError) {
// Validate against the columns we allow sorting for
if !pUtils.Contains(model.UserReportSortColumns, filter.SortColumn) {
return nil, model.NewAppError("GetUsersForReporting", "app.user.get_user_report.invalid_sort_column", nil, "", http.StatusBadRequest)
}
userReportQuery, err := a.Srv().Store().User().GetUserReport(filter)
if err != nil {
return nil, model.NewAppError("GetUsersForReporting", "app.user.get_user_report.store_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
userReports := make([]*model.UserReport, len(userReportQuery))
for i, user := range userReportQuery {
userReports[i] = user.ToReport()
}
return userReports, nil
}

Просмотреть файл

@@ -1934,31 +1934,17 @@ func TestSendSubscriptionHistoryEvent(t *testing.T) {
}
func TestGetUsersForReporting(t *testing.T) {
t.Run("should throw error on invalid page size", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
userReports, err := th.App.GetUsersForReporting(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
SortColumn: "Username",
PageSize: 999,
},
})
require.Error(t, err)
require.Nil(t, userReports)
})
t.Run("should throw error on invalid date range", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
userReports, err := th.App.GetUsersForReporting(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
StartAt: 1000,
EndAt: 500,
},
StartAt: 1000,
EndAt: 500,
})
require.Error(t, err)
require.Nil(t, userReports)
@@ -1969,7 +1955,7 @@ func TestGetUsersForReporting(t *testing.T) {
defer th.TearDown()
userReports, err := th.App.GetUsersForReporting(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "FakeColumn",
PageSize: 50,
},
@@ -2015,7 +2001,7 @@ func TestGetUsersForReporting(t *testing.T) {
mockStore.On("User").Return(&mockUserStore)
userReports, err := th.App.GetUsersForReporting(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
},

Просмотреть файл

@@ -6247,7 +6247,7 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should return info for all the users", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
},
@@ -6268,7 +6268,7 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should return in the correct order", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
SortDesc: true,
PageSize: 50,
@@ -6290,7 +6290,7 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should fail on invalid sort column", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "FakeColumn",
SortDesc: true,
PageSize: 50,
@@ -6302,7 +6302,7 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should only return amount of users in page", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 2,
},
@@ -6320,12 +6320,12 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should return correct paging", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
LastSortColumnValue: u2.Username,
LastUserId: u2.Id,
},
LastUserId: u2.Id,
})
require.NoError(t, err)
require.NotNil(t, userReport)
@@ -6337,7 +6337,7 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should return accurate post stats for various date ranges", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
},
@@ -6356,11 +6356,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, now.UnixMilli(), *userReport[2].LastPostDate)
userReport, err = ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
StartAt: now.AddDate(0, 0, -2).UnixMilli(),
},
StartAt: now.AddDate(0, 0, -2).UnixMilli(),
})
require.NoError(t, err)
require.Len(t, userReport, 3)
@@ -6376,11 +6376,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, now.UnixMilli(), *userReport[2].LastPostDate)
userReport, err = ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
EndAt: now.AddDate(0, 0, -2).UnixMilli(),
},
EndAt: now.AddDate(0, 0, -2).UnixMilli(),
})
require.NoError(t, err)
require.Len(t, userReport, 3)
@@ -6396,12 +6396,12 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[2].LastPostDate)
userReport, err = ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
StartAt: now.AddDate(0, 0, -3).UnixMilli(),
EndAt: now.AddDate(0, 0, -2).UnixMilli(),
},
StartAt: now.AddDate(0, 0, -3).UnixMilli(),
EndAt: now.AddDate(0, 0, -2).UnixMilli(),
})
require.NoError(t, err)
require.Len(t, userReport, 3)
@@ -6419,11 +6419,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should filter on roles", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
Role: "system",
},
Role: "system",
})
require.NoError(t, err)
require.Len(t, userReport, 1)
@@ -6433,11 +6433,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should filter on teams", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
HasNoTeam: true,
},
HasNoTeam: true,
})
require.NoError(t, err)
require.Len(t, userReport, 2)
@@ -6445,11 +6445,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, u2.Id, userReport[1].Id)
userReport, err = ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
Team: team.Id,
},
Team: team.Id,
})
require.NoError(t, err)
require.Len(t, userReport, 1)
@@ -6458,11 +6458,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("should filter on activation", func(t *testing.T) {
userReport, err := ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
SortColumn: "Username",
PageSize: 50,
HideInactive: true,
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
},
HideInactive: true,
})
require.NoError(t, err)
require.Len(t, userReport, 2)
@@ -6470,11 +6470,11 @@ func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, u2.Id, userReport[1].Id)
userReport, err = ss.User().GetUserReport(&model.UserReportOptions{
UserReportOptionsWithoutDateRange: model.UserReportOptionsWithoutDateRange{
ReportingBaseOptions: model.ReportingBaseOptions{
SortColumn: "Username",
PageSize: 50,
HideActive: true,
},
HideActive: true,
})
require.NoError(t, err)
require.Len(t, userReport, 1)

Просмотреть файл

@@ -2024,6 +2024,10 @@
"id": "api.getUsersForReporting.invalid_active_filter",
"translation": "Cannot hide both active and inactive users."
},
{
"id": "api.getUsersForReporting.invalid_page_size",
"translation": "Page size is invalid or too large."
},
{
"id": "api.getUsersForReporting.invalid_team_filter",
"translation": "Invalid team id provided."
@@ -6582,6 +6586,10 @@
"id": "app.recover.save.app_error",
"translation": "Unable to save the token."
},
{
"id": "app.report.get_user_report.store_error",
"translation": "Failed to fetch user report."
},
{
"id": "app.role.check_roles_exist.role_not_found",
"translation": "The provided role does not exist"
@@ -7098,26 +7106,10 @@
"id": "app.user.get_unread_count.app_error",
"translation": "We could not get the unread message count for the user."
},
{
"id": "app.user.get_user_report.invalid_sort_column",
"translation": "Provided sort column is not valid."
},
{
"id": "app.user.get_user_report.store_error",
"translation": "There was an error querying the user report."
},
{
"id": "app.user.get_users_batch_for_indexing.get_users.app_error",
"translation": "Unable to get the users batch for indexing."
},
{
"id": "app.user.get_users_for_reporting.bad_date_range",
"translation": "Date range provided is invalid."
},
{
"id": "app.user.get_users_for_reporting.invalid_page_size",
"translation": "Page size is invalid or too large."
},
{
"id": "app.user.missing_account.const",
"translation": "Unable to find the user."
@@ -9622,6 +9614,10 @@
"id": "model.reaction.is_valid.user_id.app_error",
"translation": "Invalid user id."
},
{
"id": "model.reporting_base_options.is_valid.bad_date_range",
"translation": "Date range provided is invalid."
},
{
"id": "model.search_params_list.is_valid.include_deleted_channels.app_error",
"translation": "All IncludeDeletedChannels params should have the same value."
@@ -9894,6 +9890,10 @@
"id": "model.user_access_token.is_valid.user_id.app_error",
"translation": "Invalid user id."
},
{
"id": "model.user_report_options.is_valid.invalid_sort_column",
"translation": "Provided sort column is not valid."
},
{
"id": "model.utils.decode_json.app_error",
"translation": "could not decode."

Просмотреть файл

@@ -166,6 +166,10 @@ func (c *Client4) usersRoute() string {
return "/users"
}
func (c *Client4) reportsRoute() string {
return "/reports"
}
func (c *Client4) userRoute(userId string) string {
return fmt.Sprintf(c.usersRoute()+"/%v", userId)
}
@@ -1918,7 +1922,7 @@ func (c *Client4) EnableUserAccessToken(ctx context.Context, tokenId string) (*R
return BuildResponse(r), nil
}
func (c *Client4) GetUsersForReporting(ctx context.Context, options *UserReportOptionsAPI) ([]*UserReport, *Response, error) {
func (c *Client4) GetUsersForReporting(ctx context.Context, options *UserReportOptions) ([]*UserReport, *Response, error) {
values := url.Values{}
if options.SortColumn != "" {
values.Set("sort_column", options.SortColumn)
@@ -1954,7 +1958,7 @@ func (c *Client4) GetUsersForReporting(ctx context.Context, options *UserReportO
values.Set("date_range", options.DateRange)
}
r, err := c.DoAPIGet(ctx, c.usersRoute()+"/report?"+values.Encode(), "")
r, err := c.DoAPIGet(ctx, c.reportsRoute()+"/users?"+values.Encode(), "")
if err != nil {
return nil, BuildResponse(r), err
}

109
server/public/model/report.go Обычный файл
Просмотреть файл

@@ -0,0 +1,109 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
import (
"net/http"
"time"
pUtils "github.com/mattermost/mattermost/server/public/utils"
)
const (
ReportDurationLast30Days = "last_30_days"
ReportDurationPreviousMonth = "previous_month"
ReportDurationLast6Months = "last_6_months"
ReportingMaxPageSize = 100
)
var (
UserReportSortColumns = []string{"CreateAt", "Username", "FirstName", "LastName", "Nickname", "Email", "Roles"}
)
type ReportingBaseOptions struct {
SortDesc bool
PageSize int
SortColumn string
LastSortColumnValue string
DateRange string
StartAt int64
EndAt int64
}
func (options *ReportingBaseOptions) PopulateDateRange(now time.Time) {
startAt := int64(0)
endAt := int64(0)
if options.DateRange == ReportDurationLast30Days {
startAt = now.AddDate(0, 0, -30).UnixMilli()
} else if options.DateRange == ReportDurationPreviousMonth {
startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.Local)
startAt = startOfMonth.AddDate(0, -1, 0).UnixMilli()
endAt = startOfMonth.UnixMilli()
} else if options.DateRange == ReportDurationLast6Months {
startAt = now.AddDate(0, -6, -0).UnixMilli()
}
options.StartAt = startAt
options.EndAt = endAt
}
func (options *ReportingBaseOptions) IsValid() *AppError {
if options.EndAt > 0 && options.StartAt > options.EndAt {
return NewAppError("ReportingBaseOptions.IsValid", "model.reporting_base_options.is_valid.bad_date_range", nil, "", http.StatusBadRequest)
}
return nil
}
type UserReportQuery struct {
User
UserPostStats
}
type UserReport struct {
Id string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreateAt int64 `json:"create_at,omitempty"`
DisplayName string `json:"display_name"`
Roles string `json:"roles"`
UserPostStats
}
type UserReportOptions struct {
ReportingBaseOptions
LastUserId string
Role string
Team string
HasNoTeam bool
HideActive bool
HideInactive bool
}
func (u *UserReportOptions) IsValid() *AppError {
if appErr := u.ReportingBaseOptions.IsValid(); appErr != nil {
return appErr
}
// Validate against the columns we allow sorting for
if !pUtils.Contains(UserReportSortColumns, u.SortColumn) {
return NewAppError("UserReportOptions.IsValid", "model.user_report_options.is_valid.invalid_sort_column", nil, "", http.StatusBadRequest)
}
return nil
}
func (u *UserReportQuery) ToReport() *UserReport {
return &UserReport{
Id: u.Id,
Username: u.Username,
Email: u.Email,
CreateAt: u.CreateAt,
DisplayName: u.GetDisplayName(ShowNicknameFullName),
Roles: u.Roles,
UserPostStats: u.UserPostStats,
}
}

Просмотреть файл

@@ -48,10 +48,6 @@ const (
PushThreadsNotifyProp = "push_threads"
EmailThreadsNotifyProp = "email_threads"
ReportDurationLast30Days = "last_30_days"
ReportDurationPreviousMonth = "previous_month"
ReportDurationLast6Months = "last_6_months"
DefaultLocale = "en"
UserAuthServiceEmail = "email"
@@ -71,10 +67,6 @@ const (
DesktopTokenTTL = time.Minute * 3
)
var (
UserReportSortColumns = []string{"CreateAt", "Username", "FirstName", "LastName", "Nickname", "Email", "Roles"}
)
//msgp:tuple User
// User contains the details about the user.
@@ -1029,74 +1021,3 @@ type UserPostStats struct {
DaysActive *int `json:"days_active,omitempty"`
TotalPosts *int `json:"total_posts,omitempty"`
}
type UserReportQuery struct {
User
UserPostStats
}
type UserReport struct {
Id string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreateAt int64 `json:"create_at,omitempty"`
DisplayName string `json:"display_name"`
Roles string `json:"roles"`
UserPostStats
}
type UserReportOptionsWithoutDateRange struct {
SortColumn string
SortDesc bool
PageSize int
LastSortColumnValue string
LastUserId string
Role string
Team string
HasNoTeam bool
HideActive bool
HideInactive bool
}
type UserReportOptions struct {
UserReportOptionsWithoutDateRange
StartAt int64
EndAt int64
}
type UserReportOptionsAPI struct {
UserReportOptionsWithoutDateRange
DateRange string
}
func (u *UserReportOptionsAPI) ToBaseOptions(now time.Time) *UserReportOptions {
startAt := int64(0)
endAt := int64(0)
if u.DateRange == ReportDurationLast30Days {
startAt = now.AddDate(0, 0, -30).UnixMilli()
} else if u.DateRange == ReportDurationPreviousMonth {
startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.Local)
startAt = startOfMonth.AddDate(0, -1, 0).UnixMilli()
endAt = startOfMonth.UnixMilli()
} else if u.DateRange == ReportDurationLast6Months {
startAt = now.AddDate(0, -6, -0).UnixMilli()
}
return &UserReportOptions{
UserReportOptionsWithoutDateRange: u.UserReportOptionsWithoutDateRange,
StartAt: startAt,
EndAt: endAt,
}
}
func (u *UserReportQuery) ToReport() *UserReport {
return &UserReport{
Id: u.Id,
Username: u.Username,
Email: u.Email,
CreateAt: u.CreateAt,
DisplayName: u.GetDisplayName(ShowNicknameFullName),
Roles: u.Roles,
UserPostStats: u.UserPostStats,
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу