github.com/coincircle/mattermost-server@v4.8.1-0.20180321182714-9d701c704416+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 }