mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-8497] Ability to set Do Not Disturb for a specified period of time (#16067)
* Add support for timed DND status
- accept a date time value in api query when dnd mode for user needs to be unset
- Create a new function to handle SetDNDStatus calls
- Create a scheduled task to unset dnd mode to wahtever mode was before setting it to DND
* update schema version
* Model changes to make fields more intuitive
- move dndendtime to status model
- add new field prev status in status to keep track of previous status of user
- update db migration function
- make use of prevstatus and dndendtime from status model
* set prev status and dndendtime appropriately after unsetting dnd mode
* add json tag for dndendtime
* unset dnd status only if not changed manually by user
* update dnd statuses after server restart
* make app-layers
* fix failing tests
* don't create sched task when setting status to DND
* get only expired statuses from db
- convert end time from any timezone to utc
- store dnd end time in unix format for usability reasons
* run update dnd status only on leader
* make mocks
* fix tests
* run UpdateDNDStatusOfUsers as recurring task
* save all statuses at once in db and update UpdateDNDStatusOfUsers logic
* add app method to get timezone of user
* store dnd end time in context.Params
* set max size of prevstatus
* update status model to take endtime input as string and store in db as unix time(int64)
* Add tests for SetStatusDoNotDisturbTimed
* if dnd_end_time is not passed the call old api to set dnd mode
* fix tests
* new plugin api to use new timed dnd mode
* get and update rows in a single db query
* dnd end time will be stored in request body and not route param
* exclude statuses which has dndendtimeunix < 0
* update and get the updated dnd statuses in single db query
* add updated status to cache
* DNDEndTimeUnix and PrevStatus need not to be visible to users
* update db schema version for migration
* Keep Status and PrevStatus varchar size same
* add test to verify status is restored after dnd end time expires
* expect endtime in utc from client
- remove store method GetTimezone as no longer needed
- add documentation for SetStatusDoNotDisturbTimed
* reduce sleep time for dnd timed restore test
* more appropriate name for new api to update user status
* update db migration function
* parse and validate time before potentially triggering db query to get status of user
* add migration changes in to existing upgrade function
* not supporting un-timed dnd status via api
* don't call Srv.Store directly, call via app layer
* rename dndendtime to statuscleartime to make it suitable for custom status usage as well
* Revert "rename dndendtime to statuscleartime to make it suitable for custom status usage as well"
This reverts commit fa69152d9a.
* mysql doesn't support RETURNING clause so add tx to get and update statuses
* add UpdateDNDStatusOfUsers mock in tests
* update store mock import path
* add mock in storelib
* Add status mocks to empty store
* Close the task during server shutdown
* Do not cancel a nil task
* update squirrel queries
* remove untimed dnd test
* start recurring task to unset statuses on leadership change
* set dndTask to nil after cancelling it upon server shutdown
* new recurring task which starts at nearest rounded time of the interval
* mock Get() call for status
* return updated statuses in case of mysql
* remove unneccessary code
* add Get() mock to empty store
* fix mocking for once and all
* address review comments
fix mysql updateStatus fn
protect dndTask with mutex
minor refactors
* move runDNDStatusExpireJob to server.go and pass App as arg instead of method receiver
* frontend will send endtime in unix epoch format so get rid of double representation
* scan for all fields and not just two
* add some tests and fix review comments
* remove extra sql query and create needed result in go
* add storetest for UpdateExpiredDNDStatuses
* add migrations to latest version
* update min supported version
* add comment to fix a bug in future
* update test to expect 1 status in return
* rename UpdateUserStatusWithDNDTimeout to SetUserStatusTimedDND
* rename DNDEndTimeUnix to DNDEndTime
* cast int to int64 for equality
* fix tests and error handling
* move updating values to retrieved statuses fields outside sql transaction
* move migrations to 5.36
Co-authored-by: Agniva De Sarker <agnivade@yahoo.co.in>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
@@ -229,6 +229,12 @@ type API interface {
|
||||
// Minimum server version: 5.2
|
||||
UpdateUserStatus(userID, status string) (*model.Status, *model.AppError)
|
||||
|
||||
// SetUserStatusTimedDND will set a user's status to dnd for given time until the user,
|
||||
// or another integration/plugin, sets it back to online.
|
||||
// @tag User
|
||||
// Minimum server version: 5.35
|
||||
SetUserStatusTimedDND(userId string, endtime int64) (*model.Status, *model.AppError)
|
||||
|
||||
// UpdateUserActive deactivates or reactivates an user.
|
||||
//
|
||||
// @tag User
|
||||
|
||||
@@ -266,6 +266,13 @@ func (api *apiTimerLayer) UpdateUserStatus(userID, status string) (*model.Status
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) SetUserStatusTimedDND(userId string, endtime int64) (*model.Status, *model.AppError) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := api.apiImpl.SetUserStatusTimedDND(userId, endtime)
|
||||
api.recordTime(startTime, "SetUserStatusTimedDND", _returnsB == nil)
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) UpdateUserActive(userID string, active bool) *model.AppError {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA := api.apiImpl.UpdateUserActive(userID, active)
|
||||
|
||||
@@ -1509,6 +1509,36 @@ func (s *apiRPCServer) UpdateUserStatus(args *Z_UpdateUserStatusArgs, returns *Z
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_SetUserStatusTimedDNDArgs struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
|
||||
type Z_SetUserStatusTimedDNDReturns struct {
|
||||
A *model.Status
|
||||
B *model.AppError
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) SetUserStatusTimedDND(userId string, endtime int64) (*model.Status, *model.AppError) {
|
||||
_args := &Z_SetUserStatusTimedDNDArgs{userId, endtime}
|
||||
_returns := &Z_SetUserStatusTimedDNDReturns{}
|
||||
if err := g.client.Call("Plugin.SetUserStatusTimedDND", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to SetUserStatusTimedDND API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A, _returns.B
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) SetUserStatusTimedDND(args *Z_SetUserStatusTimedDNDArgs, returns *Z_SetUserStatusTimedDNDReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
SetUserStatusTimedDND(userId string, endtime int64) (*model.Status, *model.AppError)
|
||||
}); ok {
|
||||
returns.A, returns.B = hook.SetUserStatusTimedDND(args.A, args.B)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API SetUserStatusTimedDND called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_UpdateUserActiveArgs struct {
|
||||
A string
|
||||
B bool
|
||||
|
||||
@@ -3041,6 +3041,31 @@ func (_m *API) SetTeamIcon(teamID string, data []byte) *model.AppError {
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetUserStatusTimedDND provides a mock function with given fields: userId, endtime
|
||||
func (_m *API) SetUserStatusTimedDND(userId string, endtime int64) (*model.Status, *model.AppError) {
|
||||
ret := _m.Called(userId, endtime)
|
||||
|
||||
var r0 *model.Status
|
||||
if rf, ok := ret.Get(0).(func(string, int64) *model.Status); ok {
|
||||
r0 = rf(userId, endtime)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Status)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *model.AppError
|
||||
if rf, ok := ret.Get(1).(func(string, int64) *model.AppError); ok {
|
||||
r1 = rf(userId, endtime)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*model.AppError)
|
||||
}
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UnregisterCommand provides a mock function with given fields: teamID, trigger
|
||||
func (_m *API) UnregisterCommand(teamID string, trigger string) error {
|
||||
ret := _m.Called(teamID, trigger)
|
||||
|
||||
Reference in New Issue
Block a user