github.com/demisto/mattermost-server@v4.9.0-rc3+incompatible/api4/post.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"net/http"
     8  	"strconv"
     9  	"time"
    10  
    11  	"github.com/mattermost/mattermost-server/model"
    12  )
    13  
    14  func (api *API) InitPost() {
    15  	api.BaseRoutes.Posts.Handle("", api.ApiSessionRequired(createPost)).Methods("POST")
    16  	api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(getPost)).Methods("GET")
    17  	api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(deletePost)).Methods("DELETE")
    18  	api.BaseRoutes.Post.Handle("/thread", api.ApiSessionRequired(getPostThread)).Methods("GET")
    19  	api.BaseRoutes.Post.Handle("/files/info", api.ApiSessionRequired(getFileInfosForPost)).Methods("GET")
    20  	api.BaseRoutes.PostsForChannel.Handle("", api.ApiSessionRequired(getPostsForChannel)).Methods("GET")
    21  	api.BaseRoutes.PostsForUser.Handle("/flagged", api.ApiSessionRequired(getFlaggedPostsForUser)).Methods("GET")
    22  
    23  	api.BaseRoutes.Team.Handle("/posts/search", api.ApiSessionRequired(searchPosts)).Methods("POST")
    24  	api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(updatePost)).Methods("PUT")
    25  	api.BaseRoutes.Post.Handle("/patch", api.ApiSessionRequired(patchPost)).Methods("PUT")
    26  	api.BaseRoutes.Post.Handle("/actions/{action_id:[A-Za-z0-9]+}", api.ApiSessionRequired(doPostAction)).Methods("POST")
    27  	api.BaseRoutes.Post.Handle("/pin", api.ApiSessionRequired(pinPost)).Methods("POST")
    28  	api.BaseRoutes.Post.Handle("/unpin", api.ApiSessionRequired(unpinPost)).Methods("POST")
    29  }
    30  
    31  func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
    32  	post := model.PostFromJson(r.Body)
    33  	if post == nil {
    34  		c.SetInvalidParam("post")
    35  		return
    36  	}
    37  
    38  	post.UserId = c.Session.UserId
    39  
    40  	hasPermission := false
    41  	if c.App.SessionHasPermissionToChannel(c.Session, post.ChannelId, model.PERMISSION_CREATE_POST) {
    42  		hasPermission = true
    43  	} else if channel, err := c.App.GetChannel(post.ChannelId); err == nil {
    44  		// Temporary permission check method until advanced permissions, please do not copy
    45  		if channel.Type == model.CHANNEL_OPEN && c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_POST_PUBLIC) {
    46  			hasPermission = true
    47  		}
    48  	}
    49  
    50  	if !hasPermission {
    51  		c.SetPermissionError(model.PERMISSION_CREATE_POST)
    52  		return
    53  	}
    54  
    55  	if post.CreateAt != 0 && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
    56  		post.CreateAt = 0
    57  	}
    58  
    59  	rp, err := c.App.CreatePostAsUser(c.App.PostWithProxyRemovedFromImageURLs(post))
    60  	if err != nil {
    61  		c.Err = err
    62  		return
    63  	}
    64  
    65  	c.App.SetStatusOnline(c.Session.UserId, c.Session.Id, false)
    66  	c.App.UpdateLastActivityAtIfNeeded(c.Session)
    67  
    68  	w.WriteHeader(http.StatusCreated)
    69  	w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(rp).ToJson()))
    70  }
    71  
    72  func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
    73  	c.RequireChannelId()
    74  	if c.Err != nil {
    75  		return
    76  	}
    77  
    78  	afterPost := r.URL.Query().Get("after")
    79  	beforePost := r.URL.Query().Get("before")
    80  	sinceString := r.URL.Query().Get("since")
    81  
    82  	var since int64
    83  	var parseError error
    84  
    85  	if len(sinceString) > 0 {
    86  		since, parseError = strconv.ParseInt(sinceString, 10, 64)
    87  		if parseError != nil {
    88  			c.SetInvalidParam("since")
    89  			return
    90  		}
    91  	}
    92  
    93  	if !c.App.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
    94  		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
    95  		return
    96  	}
    97  
    98  	var list *model.PostList
    99  	var err *model.AppError
   100  	etag := ""
   101  
   102  	if since > 0 {
   103  		list, err = c.App.GetPostsSince(c.Params.ChannelId, since)
   104  	} else if len(afterPost) > 0 {
   105  		etag = c.App.GetPostsEtag(c.Params.ChannelId)
   106  
   107  		if c.HandleEtag(etag, "Get Posts After", w, r) {
   108  			return
   109  		}
   110  
   111  		list, err = c.App.GetPostsAfterPost(c.Params.ChannelId, afterPost, c.Params.Page, c.Params.PerPage)
   112  	} else if len(beforePost) > 0 {
   113  		etag = c.App.GetPostsEtag(c.Params.ChannelId)
   114  
   115  		if c.HandleEtag(etag, "Get Posts Before", w, r) {
   116  			return
   117  		}
   118  
   119  		list, err = c.App.GetPostsBeforePost(c.Params.ChannelId, beforePost, c.Params.Page, c.Params.PerPage)
   120  	} else {
   121  		etag = c.App.GetPostsEtag(c.Params.ChannelId)
   122  
   123  		if c.HandleEtag(etag, "Get Posts", w, r) {
   124  			return
   125  		}
   126  
   127  		list, err = c.App.GetPostsPage(c.Params.ChannelId, c.Params.Page, c.Params.PerPage)
   128  	}
   129  
   130  	if err != nil {
   131  		c.Err = err
   132  		return
   133  	}
   134  
   135  	if len(etag) > 0 {
   136  		w.Header().Set(model.HEADER_ETAG_SERVER, etag)
   137  	}
   138  	w.Write([]byte(c.App.PostListWithProxyAddedToImageURLs(list).ToJson()))
   139  }
   140  
   141  func getFlaggedPostsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
   142  	c.RequireUserId()
   143  	if c.Err != nil {
   144  		return
   145  	}
   146  
   147  	if !c.App.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
   148  		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
   149  		return
   150  	}
   151  
   152  	channelId := r.URL.Query().Get("channel_id")
   153  	teamId := r.URL.Query().Get("team_id")
   154  
   155  	var posts *model.PostList
   156  	var err *model.AppError
   157  
   158  	if len(channelId) > 0 {
   159  		posts, err = c.App.GetFlaggedPostsForChannel(c.Params.UserId, channelId, c.Params.Page, c.Params.PerPage)
   160  	} else if len(teamId) > 0 {
   161  		posts, err = c.App.GetFlaggedPostsForTeam(c.Params.UserId, teamId, c.Params.Page, c.Params.PerPage)
   162  	} else {
   163  		posts, err = c.App.GetFlaggedPosts(c.Params.UserId, c.Params.Page, c.Params.PerPage)
   164  	}
   165  
   166  	if err != nil {
   167  		c.Err = err
   168  		return
   169  	}
   170  
   171  	w.Write([]byte(c.App.PostListWithProxyAddedToImageURLs(posts).ToJson()))
   172  }
   173  
   174  func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
   175  	c.RequirePostId()
   176  	if c.Err != nil {
   177  		return
   178  	}
   179  
   180  	var post *model.Post
   181  	var err *model.AppError
   182  	if post, err = c.App.GetSinglePost(c.Params.PostId); err != nil {
   183  		c.Err = err
   184  		return
   185  	}
   186  
   187  	var channel *model.Channel
   188  	if channel, err = c.App.GetChannel(post.ChannelId); err != nil {
   189  		c.Err = err
   190  		return
   191  	}
   192  
   193  	if !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
   194  		if channel.Type == model.CHANNEL_OPEN {
   195  			if !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
   196  				c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
   197  				return
   198  			}
   199  		} else {
   200  			c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
   201  			return
   202  		}
   203  	}
   204  
   205  	if c.HandleEtag(post.Etag(), "Get Post", w, r) {
   206  		return
   207  	} else {
   208  		w.Header().Set(model.HEADER_ETAG_SERVER, post.Etag())
   209  		w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(post).ToJson()))
   210  	}
   211  }
   212  
   213  func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
   214  	c.RequirePostId()
   215  	if c.Err != nil {
   216  		return
   217  	}
   218  
   219  	if !c.App.SessionHasPermissionToPost(c.Session, c.Params.PostId, model.PERMISSION_DELETE_OTHERS_POSTS) {
   220  		c.SetPermissionError(model.PERMISSION_DELETE_OTHERS_POSTS)
   221  		return
   222  	}
   223  
   224  	if _, err := c.App.DeletePost(c.Params.PostId); err != nil {
   225  		c.Err = err
   226  		return
   227  	}
   228  
   229  	ReturnStatusOK(w)
   230  }
   231  
   232  func getPostThread(c *Context, w http.ResponseWriter, r *http.Request) {
   233  	c.RequirePostId()
   234  	if c.Err != nil {
   235  		return
   236  	}
   237  
   238  	var list *model.PostList
   239  	var err *model.AppError
   240  	if list, err = c.App.GetPostThread(c.Params.PostId); err != nil {
   241  		c.Err = err
   242  		return
   243  	}
   244  
   245  	var post *model.Post
   246  	if val, ok := list.Posts[c.Params.PostId]; ok {
   247  		post = val
   248  	} else {
   249  		c.SetInvalidUrlParam("post_id")
   250  		return
   251  	}
   252  
   253  	var channel *model.Channel
   254  	if channel, err = c.App.GetChannel(post.ChannelId); err != nil {
   255  		c.Err = err
   256  		return
   257  	}
   258  
   259  	if !c.App.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
   260  		if channel.Type == model.CHANNEL_OPEN {
   261  			if !c.App.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
   262  				c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
   263  				return
   264  			}
   265  		} else {
   266  			c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
   267  			return
   268  		}
   269  	}
   270  
   271  	if c.HandleEtag(list.Etag(), "Get Post Thread", w, r) {
   272  		return
   273  	} else {
   274  		w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag())
   275  		w.Write([]byte(c.App.PostListWithProxyAddedToImageURLs(list).ToJson()))
   276  	}
   277  }
   278  
   279  func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
   280  	c.RequireTeamId()
   281  	if c.Err != nil {
   282  		return
   283  	}
   284  
   285  	if !c.App.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
   286  		c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
   287  		return
   288  	}
   289  
   290  	props := model.StringInterfaceFromJson(r.Body)
   291  	terms, ok := props["terms"].(string)
   292  	if !ok || len(terms) == 0 {
   293  		c.SetInvalidParam("terms")
   294  		return
   295  	}
   296  
   297  	isOrSearch, _ := props["is_or_search"].(bool)
   298  
   299  	startTime := time.Now()
   300  
   301  	posts, err := c.App.SearchPostsInTeam(terms, c.Session.UserId, c.Params.TeamId, isOrSearch)
   302  
   303  	elapsedTime := float64(time.Since(startTime)) / float64(time.Second)
   304  	metrics := c.App.Metrics
   305  	if metrics != nil {
   306  		metrics.IncrementPostsSearchCounter()
   307  		metrics.ObservePostsSearchDuration(elapsedTime)
   308  	}
   309  
   310  	if err != nil {
   311  		c.Err = err
   312  		return
   313  	}
   314  
   315  	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
   316  	w.Write([]byte(c.App.PostListWithProxyAddedToImageURLs(posts).ToJson()))
   317  }
   318  
   319  func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
   320  	c.RequirePostId()
   321  	if c.Err != nil {
   322  		return
   323  	}
   324  
   325  	post := model.PostFromJson(r.Body)
   326  
   327  	if post == nil {
   328  		c.SetInvalidParam("post")
   329  		return
   330  	}
   331  
   332  	if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_EDIT_POST) {
   333  		c.SetPermissionError(model.PERMISSION_EDIT_POST)
   334  		return
   335  	}
   336  
   337  	if !c.App.SessionHasPermissionToPost(c.Session, c.Params.PostId, model.PERMISSION_EDIT_OTHERS_POSTS) {
   338  		c.SetPermissionError(model.PERMISSION_EDIT_OTHERS_POSTS)
   339  		return
   340  	}
   341  
   342  	post.Id = c.Params.PostId
   343  
   344  	rpost, err := c.App.UpdatePost(c.App.PostWithProxyRemovedFromImageURLs(post), false)
   345  	if err != nil {
   346  		c.Err = err
   347  		return
   348  	}
   349  
   350  	w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(rpost).ToJson()))
   351  }
   352  
   353  func patchPost(c *Context, w http.ResponseWriter, r *http.Request) {
   354  	c.RequirePostId()
   355  	if c.Err != nil {
   356  		return
   357  	}
   358  
   359  	post := model.PostPatchFromJson(r.Body)
   360  
   361  	if post == nil {
   362  		c.SetInvalidParam("post")
   363  		return
   364  	}
   365  
   366  	if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_EDIT_POST) {
   367  		c.SetPermissionError(model.PERMISSION_EDIT_POST)
   368  		return
   369  	}
   370  
   371  	if !c.App.SessionHasPermissionToPost(c.Session, c.Params.PostId, model.PERMISSION_EDIT_OTHERS_POSTS) {
   372  		c.SetPermissionError(model.PERMISSION_EDIT_OTHERS_POSTS)
   373  		return
   374  	}
   375  
   376  	patchedPost, err := c.App.PatchPost(c.Params.PostId, c.App.PostPatchWithProxyRemovedFromImageURLs(post))
   377  	if err != nil {
   378  		c.Err = err
   379  		return
   380  	}
   381  
   382  	w.Write([]byte(c.App.PostWithProxyAddedToImageURLs(patchedPost).ToJson()))
   383  }
   384  
   385  func saveIsPinnedPost(c *Context, w http.ResponseWriter, r *http.Request, isPinned bool) {
   386  	c.RequirePostId()
   387  	if c.Err != nil {
   388  		return
   389  	}
   390  
   391  	if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
   392  		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
   393  		return
   394  	}
   395  
   396  	patch := &model.PostPatch{}
   397  	patch.IsPinned = model.NewBool(isPinned)
   398  
   399  	_, err := c.App.PatchPost(c.Params.PostId, patch)
   400  	if err != nil {
   401  		c.Err = err
   402  		return
   403  	}
   404  
   405  	ReturnStatusOK(w)
   406  }
   407  
   408  func pinPost(c *Context, w http.ResponseWriter, r *http.Request) {
   409  	saveIsPinnedPost(c, w, r, true)
   410  }
   411  
   412  func unpinPost(c *Context, w http.ResponseWriter, r *http.Request) {
   413  	saveIsPinnedPost(c, w, r, false)
   414  }
   415  
   416  func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
   417  	c.RequirePostId()
   418  	if c.Err != nil {
   419  		return
   420  	}
   421  
   422  	if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
   423  		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
   424  		return
   425  	}
   426  
   427  	if infos, err := c.App.GetFileInfosForPost(c.Params.PostId, false); err != nil {
   428  		c.Err = err
   429  		return
   430  	} else if c.HandleEtag(model.GetEtagForFileInfos(infos), "Get File Infos For Post", w, r) {
   431  		return
   432  	} else {
   433  		w.Header().Set("Cache-Control", "max-age=2592000, public")
   434  		w.Header().Set(model.HEADER_ETAG_SERVER, model.GetEtagForFileInfos(infos))
   435  		w.Write([]byte(model.FileInfosToJson(infos)))
   436  	}
   437  }
   438  
   439  func doPostAction(c *Context, w http.ResponseWriter, r *http.Request) {
   440  	c.RequirePostId().RequireActionId()
   441  	if c.Err != nil {
   442  		return
   443  	}
   444  
   445  	if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
   446  		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
   447  		return
   448  	}
   449  
   450  	if err := c.App.DoPostAction(c.Params.PostId, c.Params.ActionId, c.Session.UserId); err != nil {
   451  		c.Err = err
   452  		return
   453  	}
   454  
   455  	ReturnStatusOK(w)
   456  }