From 997df03ac1455785b7a39e40edcd67b3b3e86f9e Mon Sep 17 00:00:00 2001 From: Daniel Schalla Date: Tue, 17 Apr 2018 14:20:47 +0200 Subject: Initial Commit of Ephemeral Message Support for System Admins (#8611) Fixed Permission Test Fixed and extended ephemeral message tests; Removed Online/Activity Updates Set Create Time to current time gofmt --- api4/post.go | 30 ++++++++++++++++++++++++++++++ api4/post_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ app/app_test.go | 2 ++ model/client4.go | 14 ++++++++++++++ model/permission.go | 8 ++++++++ model/post.go | 10 ++++++++++ model/role.go | 1 + 7 files changed, 106 insertions(+) diff --git a/api4/post.go b/api4/post.go index 80088d9ef..189edfc20 100644 --- a/api4/post.go +++ b/api4/post.go @@ -4,6 +4,7 @@ package api4 import ( + "encoding/json" "net/http" "strconv" "time" @@ -15,6 +16,7 @@ func (api *API) InitPost() { api.BaseRoutes.Posts.Handle("", api.ApiSessionRequired(createPost)).Methods("POST") api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(getPost)).Methods("GET") api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(deletePost)).Methods("DELETE") + api.BaseRoutes.Posts.Handle("/ephemeral", api.ApiSessionRequired(createEphemeralPost)).Methods("POST") api.BaseRoutes.Post.Handle("/thread", api.ApiSessionRequired(getPostThread)).Methods("GET") api.BaseRoutes.Post.Handle("/files/info", api.ApiSessionRequired(getFileInfosForPost)).Methods("GET") api.BaseRoutes.PostsForChannel.Handle("", api.ApiSessionRequired(getPostsForChannel)).Methods("GET") @@ -69,6 +71,34 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(rp).ToJson())) } +func createEphemeralPost(c *Context, w http.ResponseWriter, r *http.Request) { + ephRequest := model.PostEphemeral{} + + json.NewDecoder(r.Body).Decode(&ephRequest) + if ephRequest.UserID == "" { + c.SetInvalidParam("user_id") + return + } + + if ephRequest.Post == nil { + c.SetInvalidParam("post") + return + } + + ephRequest.Post.UserId = c.Session.UserId + ephRequest.Post.CreateAt = model.GetMillis() + + if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_POST_EPHEMERAL) { + c.SetPermissionError(model.PERMISSION_CREATE_POST_EPHEMERAL) + return + } + + rp := c.App.SendEphemeralPost(ephRequest.UserID, c.App.PostWithProxyRemovedFromImageURLs(ephRequest.Post)) + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(rp).ToJson())) +} + func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) { c.RequireChannelId() if c.Err != nil { diff --git a/api4/post_test.go b/api4/post_test.go index 1b682e38b..63d71b5bd 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -116,6 +116,47 @@ func TestCreatePost(t *testing.T) { } } +func TestCreatePostEphemeral(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + Client := th.SystemAdminClient + + ephemeralPost := &model.PostEphemeral{ + UserID: th.BasicUser2.Id, + Post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}}, + } + + rpost, resp := Client.CreatePostEphemeral(ephemeralPost) + CheckNoError(t, resp) + CheckCreatedStatus(t, resp) + + if rpost.Message != ephemeralPost.Post.Message { + t.Fatal("message didn't match") + } + + if rpost.EditAt != 0 { + t.Fatal("newly created ephemeral post shouldn't have EditAt set") + } + + if r, err := Client.DoApiPost("/posts/ephemeral", "garbage"); err == nil { + t.Fatal("should have errored") + } else { + if r.StatusCode != http.StatusBadRequest { + t.Log("actual: " + strconv.Itoa(r.StatusCode)) + t.Log("expected: " + strconv.Itoa(http.StatusBadRequest)) + t.Fatal("wrong status code") + } + } + + Client.Logout() + _, resp = Client.CreatePostEphemeral(ephemeralPost) + CheckUnauthorizedStatus(t, resp) + + Client = th.Client + rpost, resp = Client.CreatePostEphemeral(ephemeralPost) + CheckForbiddenStatus(t, resp) +} + func testCreatePostWithOutgoingHook( t *testing.T, hookContentType, expectedContentType, message, triggerWord string, diff --git a/app/app_test.go b/app/app_test.go index c2841ec53..a726fc2b5 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -195,6 +195,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, model.PERMISSION_MANAGE_JOBS.Id, model.PERMISSION_CREATE_POST_PUBLIC.Id, + model.PERMISSION_CREATE_POST_EPHEMERAL.Id, model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, @@ -359,6 +360,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { model.PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, model.PERMISSION_MANAGE_JOBS.Id, model.PERMISSION_CREATE_POST_PUBLIC.Id, + model.PERMISSION_CREATE_POST_EPHEMERAL.Id, model.PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, model.PERMISSION_READ_USER_ACCESS_TOKEN.Id, model.PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, diff --git a/model/client4.go b/model/client4.go index 82d380440..f1feb1bfe 100644 --- a/model/client4.go +++ b/model/client4.go @@ -162,6 +162,10 @@ func (c *Client4) GetPostsRoute() string { return fmt.Sprintf("/posts") } +func (c *Client4) GetPostsEphemeralRoute() string { + return fmt.Sprintf("/posts/ephemeral") +} + func (c *Client4) GetConfigRoute() string { return fmt.Sprintf("/config") } @@ -1771,6 +1775,16 @@ func (c *Client4) CreatePost(post *Post) (*Post, *Response) { } } +// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id +func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) { + if r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()); err != nil { + return nil, BuildErrorResponse(r, err) + } else { + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) + } +} + // UpdatePost updates a post based on the provided post struct. func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) { if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()); err != nil { diff --git a/model/permission.go b/model/permission.go index 703f6c71e..792c7d42e 100644 --- a/model/permission.go +++ b/model/permission.go @@ -52,6 +52,7 @@ var PERMISSION_MANAGE_OAUTH *Permission var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission var PERMISSION_CREATE_POST *Permission var PERMISSION_CREATE_POST_PUBLIC *Permission +var PERMISSION_CREATE_POST_EPHEMERAL *Permission var PERMISSION_EDIT_POST *Permission var PERMISSION_EDIT_OTHERS_POSTS *Permission var PERMISSION_DELETE_POST *Permission @@ -297,6 +298,12 @@ func initializePermissions() { "authentication.permissions.create_post_public.description", PERMISSION_SCOPE_CHANNEL, } + PERMISSION_CREATE_POST_EPHEMERAL = &Permission{ + "create_post_ephemeral", + "authentication.permissions.create_post_ephemeral.name", + "authentication.permissions.create_post_ephemeral.description", + PERMISSION_SCOPE_CHANNEL, + } PERMISSION_EDIT_POST = &Permission{ "edit_post", "authentication.permissions.edit_post.name", @@ -419,6 +426,7 @@ func initializePermissions() { PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, PERMISSION_CREATE_POST, PERMISSION_CREATE_POST_PUBLIC, + PERMISSION_CREATE_POST_EPHEMERAL, PERMISSION_EDIT_POST, PERMISSION_EDIT_OTHERS_POSTS, PERMISSION_DELETE_POST, diff --git a/model/post.go b/model/post.go index e74496979..31837b8c8 100644 --- a/model/post.go +++ b/model/post.go @@ -80,6 +80,11 @@ type Post struct { HasReactions bool `json:"has_reactions,omitempty"` } +type PostEphemeral struct { + UserID string `json:"user_id"` + Post *Post `json:"post"` +} + type PostPatch struct { IsPinned *bool `json:"is_pinned"` Message *string `json:"message"` @@ -432,6 +437,11 @@ func (o *Post) WithRewrittenImageURLs(f func(string) string) *Post { return © } +func (o *PostEphemeral) ToUnsanitizedJson() string { + b, _ := json.Marshal(o) + return string(b) +} + // RewriteImageURLs takes a message and returns a copy that has all of the image URLs replaced // according to the function f. For each image URL, f will be invoked, and the resulting markdown // will contain the URL returned by that invocation instead. diff --git a/model/role.go b/model/role.go index 5c2cf8f5b..f10b52537 100644 --- a/model/role.go +++ b/model/role.go @@ -330,6 +330,7 @@ func MakeDefaultRoles() map[string]*Role { PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, PERMISSION_MANAGE_JOBS.Id, PERMISSION_CREATE_POST_PUBLIC.Id, + PERMISSION_CREATE_POST_EPHEMERAL.Id, PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, PERMISSION_READ_USER_ACCESS_TOKEN.Id, PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, -- cgit v1.2.3-1-g7c22