diff --git a/api4/status.go b/api4/status.go index 6f717bb26b..dc57908811 100644 --- a/api4/status.go +++ b/api4/status.go @@ -127,7 +127,7 @@ func updateUserCustomStatus(c *Context, w http.ResponseWriter, r *http.Request) } customStatus := model.CustomStatusFromJson(r.Body) - if customStatus == nil || (customStatus.Text == "" && customStatus.Emoji == "") { + if customStatus == nil || (customStatus.Emoji == "" && customStatus.Text == "") || !customStatus.AreDurationAndExpirationTimeValid() { c.SetInvalidParam("custom_status") return } @@ -137,7 +137,7 @@ func updateUserCustomStatus(c *Context, w http.ResponseWriter, r *http.Request) return } - customStatus.TrimMessage() + customStatus.PreSave() err := c.App.SetCustomStatus(c.Params.UserId, customStatus) if err != nil { c.Err = err diff --git a/app/slashcommands/command_custom_status.go b/app/slashcommands/command_custom_status.go index 926812ad47..4f8bab8be4 100644 --- a/app/slashcommands/command_custom_status.go +++ b/app/slashcommands/command_custom_status.go @@ -21,8 +21,6 @@ type CustomStatusProvider struct { const ( CmdCustomStatus = app.CmdCustomStatusTrigger CmdCustomStatusClear = "clear" - - DefaultCustomStatusEmoji = "speech_balloon" ) func init() { @@ -62,6 +60,7 @@ func (*CustomStatusProvider) DoCommand(a *app.App, c *request.Context, args *mod } customStatus := GetCustomStatus(message) + customStatus.PreSave() if err := a.SetCustomStatus(args.UserId, customStatus); err != nil { mlog.Debug(err.Error()) return &model.CommandResponse{Text: args.T("api.command_custom_status.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} @@ -78,7 +77,7 @@ func (*CustomStatusProvider) DoCommand(a *app.App, c *request.Context, args *mod func GetCustomStatus(message string) *model.CustomStatus { customStatus := &model.CustomStatus{ - Emoji: DefaultCustomStatusEmoji, + Emoji: model.DefaultCustomStatusEmoji, Text: message, } @@ -87,7 +86,6 @@ func GetCustomStatus(message string) *model.CustomStatus { // emoji found at starting index customStatus.Emoji = message[firstEmojiLocations[0]+1 : firstEmojiLocations[1]-1] customStatus.Text = strings.TrimSpace(message[firstEmojiLocations[1]:]) - customStatus.TrimMessage() return customStatus } @@ -117,7 +115,6 @@ func GetCustomStatus(message string) *model.CustomStatus { customStatus.Text = strings.TrimSpace(textString) } - customStatus.TrimMessage() return customStatus } diff --git a/app/slashcommands/command_custom_status_test.go b/app/slashcommands/command_custom_status_test.go index 4e99dad52e..c2b05a0eb7 100644 --- a/app/slashcommands/command_custom_status_test.go +++ b/app/slashcommands/command_custom_status_test.go @@ -11,14 +11,14 @@ import ( func TestGetCustomStatus(t *testing.T) { for msg, expected := range map[string]model.CustomStatus{ - "": {Emoji: DefaultCustomStatusEmoji, Text: ""}, - "Hey": {Emoji: DefaultCustomStatusEmoji, Text: "Hey"}, + "": {Emoji: model.DefaultCustomStatusEmoji, Text: ""}, + "Hey": {Emoji: model.DefaultCustomStatusEmoji, Text: "Hey"}, ":cactus: Hurt": {Emoji: "cactus", Text: "Hurt"}, "👅": {Emoji: "tongue", Text: ""}, "👅 Eating": {Emoji: "tongue", Text: "Eating"}, "💪🏻 Working out": {Emoji: "muscle_light_skin_tone", Text: "Working out"}, "👙 Swimming": {Emoji: "bikini", Text: "Swimming"}, - "👙Swimming": {Emoji: DefaultCustomStatusEmoji, Text: "👙Swimming"}, + "👙Swimming": {Emoji: model.DefaultCustomStatusEmoji, Text: "👙Swimming"}, "👍🏿 Okay": {Emoji: "+1_dark_skin_tone", Text: "Okay"}, "🤴🏾 Dark king": {Emoji: "prince_medium_dark_skin_tone", Text: "Dark king"}, "⛹🏾‍♀️ Playing basketball": {Emoji: "basketball_woman", Text: "Playing basketball"}, diff --git a/model/custom_status.go b/model/custom_status.go index 68e78e4d29..9898ce6c4d 100644 --- a/model/custom_status.go +++ b/model/custom_status.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io" + "time" ) const ( @@ -14,14 +15,34 @@ const ( CustomStatusTextMaxRunes = 100 MaxRecentCustomStatuses = 5 + DefaultCustomStatusEmoji = "speech_balloon" ) -type CustomStatus struct { - Emoji string `json:"emoji"` - Text string `json:"text"` +var validCustomStatusDuration = map[string]bool{ + "thirty_minutes": true, + "one_hour": true, + "four_hours": true, + "today": true, + "this_week": true, + "date_and_time": true, } -func (cs *CustomStatus) TrimMessage() { +type CustomStatus struct { + Emoji string `json:"emoji"` + Text string `json:"text"` + Duration string `json:"duration"` + ExpiresAt time.Time `json:"expires_at"` +} + +func (cs *CustomStatus) PreSave() { + if cs.Emoji == "" { + cs.Emoji = DefaultCustomStatusEmoji + } + + if cs.Duration == "" && !cs.ExpiresAt.Before(time.Now()) { + cs.Duration = "date_and_time" + } + runes := []rune(cs.Text) if len(runes) > CustomStatusTextMaxRunes { cs.Text = string(runes[:CustomStatusTextMaxRunes]) @@ -34,6 +55,18 @@ func (cs *CustomStatus) ToJson() string { return string(b) } +func (cs *CustomStatus) AreDurationAndExpirationTimeValid() bool { + if cs.Duration == "" && (cs.ExpiresAt.IsZero() || !cs.ExpiresAt.Before(time.Now())) { + return true + } + + if validCustomStatusDuration[cs.Duration] && !cs.ExpiresAt.Before(time.Now()) { + return true + } + + return false +} + func CustomStatusFromJson(data io.Reader) *CustomStatus { var cs *CustomStatus _ = json.NewDecoder(data).Decode(&cs)