PLT-3921 Fix System Console Recent Active Users (#3856)

* PLT-3921 System Console Recent Active Users
Этот коммит содержится в:
enahum
2016-09-06 15:48:43 -03:00
коммит произвёл GitHub
родитель 9a9ae3dcd1
Коммит 35b816b922
9 изменённых файлов: 99 добавлений и 1 удалений

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

@@ -48,6 +48,7 @@ func InitAdmin() {
BaseRoutes.Admin.Handle("/remove_certificate", ApiAdminSystemRequired(removeCertificate)).Methods("POST") BaseRoutes.Admin.Handle("/remove_certificate", ApiAdminSystemRequired(removeCertificate)).Methods("POST")
BaseRoutes.Admin.Handle("/saml_cert_status", ApiAdminSystemRequired(samlCertificateStatus)).Methods("GET") BaseRoutes.Admin.Handle("/saml_cert_status", ApiAdminSystemRequired(samlCertificateStatus)).Methods("GET")
BaseRoutes.Admin.Handle("/cluster_status", ApiAdminSystemRequired(getClusterStatus)).Methods("GET") BaseRoutes.Admin.Handle("/cluster_status", ApiAdminSystemRequired(getClusterStatus)).Methods("GET")
BaseRoutes.Admin.Handle("/recently_active_users/{team_id:[A-Za-z0-9]+}", ApiUserRequiredActivity(getRecentlyActiveUsers, false)).Methods("GET")
} }
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -754,3 +755,37 @@ func samlCertificateStatus(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.StringInterfaceToJson(status))) w.Write([]byte(model.StringInterfaceToJson(status)))
} }
func getRecentlyActiveUsers(c *Context, w http.ResponseWriter, r *http.Request) {
statusMap := map[string]interface{}{}
if result := <-Srv.Store.Status().GetAllFromTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
statuses := result.Data.([]*model.Status)
for _, s := range statuses {
statusMap[s.UserId] = s.LastActivityAt
}
}
if result := <-Srv.Store.User().GetProfiles(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
profiles := result.Data.(map[string]*model.User)
for k, p := range profiles {
p = sanitizeProfile(c, p)
if lastActivityAt, ok := statusMap[p.Id].(int64); ok {
p.LastActivityAt = lastActivityAt
}
profiles[k] = p
}
w.Write([]byte(model.UserMapToJson(profiles)))
}
}

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

@@ -527,3 +527,18 @@ func TestAdminLdapSyncNow(t *testing.T) {
t.Fatal("Returned Failure") t.Fatal("Returned Failure")
} }
} }
func TestGetRecentlyActiveUsers(t *testing.T) {
th := Setup().InitBasic()
user1Id := th.BasicUser.Id
user2Id := th.BasicUser2.Id
if userMap, err := th.BasicClient.GetRecentlyActiveUsers(th.BasicTeam.Id); err != nil {
t.Fatal(err)
} else if len(userMap.Data.(map[string]*model.User)) != 2 {
t.Fatal("should have been 2")
} else if userMap.Data.(map[string]*model.User)[user1Id].Id != user1Id || userMap.Data.(map[string]*model.User)[user2Id].Id != user2Id {
t.Fatal("should have been valid")
}
}

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

@@ -4283,6 +4283,10 @@
"id": "store.sql_status.get_online_away.app_error", "id": "store.sql_status.get_online_away.app_error",
"translation": "Encountered an error retrieving all the online/away statuses" "translation": "Encountered an error retrieving all the online/away statuses"
}, },
{
"id": "store.sql_status.get_team_statuses.app_error",
"translation": "Encountered an error retrieving all statuses from the team members"
},
{ {
"id": "store.sql_status.get_total_active_users_count.app_error", "id": "store.sql_status.get_total_active_users_count.app_error",
"translation": "We could not count the active users" "translation": "We could not count the active users"

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

@@ -820,6 +820,17 @@ func (c *Client) GetClusterStatus() ([]*ClusterInfo, *AppError) {
} }
} }
// GetRecentlyActiveUsers returns a map of users including lastActivityAt using user id as the key
func (c *Client) GetRecentlyActiveUsers(teamId string) (*Result, *AppError) {
if r, err := c.DoApiGet("/admin/recently_active_users/"+teamId, "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
}
}
func (c *Client) GetAllAudits() (*Result, *AppError) { func (c *Client) GetAllAudits() (*Result, *AppError) {
if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil { if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
return nil, err return nil, err

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

@@ -48,6 +48,7 @@ type User struct {
Locale string `json:"locale"` Locale string `json:"locale"`
MfaActive bool `json:"mfa_active,omitempty"` MfaActive bool `json:"mfa_active,omitempty"`
MfaSecret string `json:"mfa_secret,omitempty"` MfaSecret string `json:"mfa_secret,omitempty"`
LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"`
} }
// IsValid validates the user and returns an error if it isn't configured // IsValid validates the user and returns an error if it isn't configured

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

@@ -129,6 +129,28 @@ func (s SqlStatusStore) GetOnline() StoreChannel {
return storeChannel return storeChannel
} }
func (s SqlStatusStore) GetAllFromTeam(teamId string) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
var statuses []*model.Status
if _, err := s.GetReplica().Select(&statuses,
`SELECT s.* FROM Status AS s INNER JOIN
TeamMembers AS tm ON tm.TeamId=:TeamId AND s.UserId=tm.UserId`, map[string]interface{}{"TeamId": teamId}); err != nil {
result.Err = model.NewLocAppError("SqlStatusStore.GetAllFromTeam", "store.sql_status.get_team_statuses.app_error", nil, err.Error())
} else {
result.Data = statuses
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlStatusStore) ResetAll() StoreChannel { func (s SqlStatusStore) ResetAll() StoreChannel {
storeChannel := make(StoreChannel) storeChannel := make(StoreChannel)

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

@@ -275,6 +275,7 @@ type StatusStore interface {
Get(userId string) StoreChannel Get(userId string) StoreChannel
GetOnlineAway() StoreChannel GetOnlineAway() StoreChannel
GetOnline() StoreChannel GetOnline() StoreChannel
GetAllFromTeam(teamId string) StoreChannel
ResetAll() StoreChannel ResetAll() StoreChannel
GetTotalActiveUsersCount() StoreChannel GetTotalActiveUsersCount() StoreChannel
UpdateLastActivityAt(userId string, lastActivityAt int64) StoreChannel UpdateLastActivityAt(userId string, lastActivityAt int64) StoreChannel

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

@@ -958,6 +958,15 @@ export default class Client {
end(this.handleResponse.bind(this, 'getAudits', success, error)); end(this.handleResponse.bind(this, 'getAudits', success, error));
} }
getRecentlyActiveUsers(id, success, error) {
request.
get(`${this.getAdminRoute()}/recently_active_users/${id}`).
set(this.defaultHeaders).
type('application/json').
accept('application/json').
end(this.handleResponse.bind(this, 'getRecentlyActiveUsers', success, error));
}
getDirectProfiles(success, error) { getDirectProfiles(success, error) {
request. request.
get(`${this.getUsersRoute()}/direct_profiles`). get(`${this.getUsersRoute()}/direct_profiles`).

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

@@ -1138,7 +1138,7 @@ export function getRecentAndNewUsersAnalytics(teamId) {
callTracker[callName] = utils.getTimestamp(); callTracker[callName] = utils.getTimestamp();
Client.getProfilesForTeam( Client.getRecentlyActiveUsers(
teamId, teamId,
(users) => { (users) => {
const stats = {}; const stats = {};