post.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
  2. // See LICENSE.txt for license information.
  3. package api4
  4. import (
  5. "encoding/json"
  6. "net/http"
  7. "strconv"
  8. "time"
  9. "github.com/mattermost/mattermost-server/v5/app"
  10. "github.com/mattermost/mattermost-server/v5/audit"
  11. "github.com/mattermost/mattermost-server/v5/mlog"
  12. "github.com/mattermost/mattermost-server/v5/model"
  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.Posts.Handle("/ephemeral", api.ApiSessionRequired(createEphemeralPost)).Methods("POST")
  19. api.BaseRoutes.Post.Handle("/thread", api.ApiSessionRequired(getPostThread)).Methods("GET")
  20. api.BaseRoutes.Post.Handle("/files/info", api.ApiSessionRequired(getFileInfosForPost)).Methods("GET")
  21. api.BaseRoutes.PostsForChannel.Handle("", api.ApiSessionRequired(getPostsForChannel)).Methods("GET")
  22. api.BaseRoutes.PostsForUser.Handle("/flagged", api.ApiSessionRequired(getFlaggedPostsForUser)).Methods("GET")
  23. api.BaseRoutes.ChannelForUser.Handle("/posts/unread", api.ApiSessionRequired(getPostsForChannelAroundLastUnread)).Methods("GET")
  24. api.BaseRoutes.Team.Handle("/posts/search", api.ApiSessionRequiredDisableWhenBusy(searchPosts)).Methods("POST")
  25. api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(updatePost)).Methods("PUT")
  26. api.BaseRoutes.Post.Handle("/patch", api.ApiSessionRequired(patchPost)).Methods("PUT")
  27. api.BaseRoutes.PostForUser.Handle("/set_unread", api.ApiSessionRequired(setPostUnread)).Methods("POST")
  28. api.BaseRoutes.Post.Handle("/pin", api.ApiSessionRequired(pinPost)).Methods("POST")
  29. api.BaseRoutes.Post.Handle("/unpin", api.ApiSessionRequired(unpinPost)).Methods("POST")
  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. post.UserId = c.App.Session().UserId
  38. auditRec := c.MakeAuditRecord("createPost", audit.Fail)
  39. defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
  40. auditRec.AddMeta("post", post)
  41. hasPermission := false
  42. if c.App.SessionHasPermissionToChannel(*c.App.Session(), post.ChannelId, model.PERMISSION_CREATE_POST) {
  43. hasPermission = true
  44. } else if channel, err := c.App.GetChannel(post.ChannelId); err == nil {
  45. // Temporary permission check method until advanced permissions, please do not copy
  46. if channel.Type == model.CHANNEL_OPEN && c.App.SessionHasPermissionToTeam(*c.App.Session(), channel.TeamId, model.PERMISSION_CREATE_POST_PUBLIC) {
  47. hasPermission = true
  48. }
  49. }
  50. if !hasPermission {
  51. c.SetPermissionError(model.PERMISSION_CREATE_POST)
  52. return
  53. }
  54. if post.CreateAt != 0 && !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
  55. post.CreateAt = 0
  56. }
  57. setOnline := r.URL.Query().Get("set_online")
  58. setOnlineBool := true // By default, always set online.
  59. var err2 error
  60. if setOnline != "" {
  61. setOnlineBool, err2 = strconv.ParseBool(setOnline)
  62. if err2 != nil {
  63. mlog.Warn("Failed to parse set_online URL query parameter from createPost request", mlog.Err(err2))
  64. setOnlineBool = true // Set online nevertheless.
  65. }
  66. }
  67. rp, err := c.App.CreatePostAsUser(c.App.PostWithProxyRemovedFromImageURLs(post), c.App.Session().Id, setOnlineBool)
  68. if err != nil {
  69. c.Err = err
  70. return
  71. }
  72. auditRec.Success()
  73. auditRec.AddMeta("post", rp) // overwrite meta
  74. if setOnlineBool {
  75. c.App.SetStatusOnline(c.App.Session().UserId, false)
  76. }
  77. c.App.UpdateLastActivityAtIfNeeded(*c.App.Session())
  78. c.ExtendSessionExpiryIfNeeded(w, r)
  79. w.WriteHeader(http.StatusCreated)
  80. // Note that rp has already had PreparePostForClient called on it by App.CreatePost
  81. w.Write([]byte(rp.ToJson()))
  82. }
  83. func createEphemeralPost(c *Context, w http.ResponseWriter, r *http.Request) {
  84. ephRequest := model.PostEphemeral{}
  85. json.NewDecoder(r.Body).Decode(&ephRequest)
  86. if ephRequest.UserID == "" {
  87. c.SetInvalidParam("user_id")
  88. return
  89. }
  90. if ephRequest.Post == nil {
  91. c.SetInvalidParam("post")
  92. return
  93. }
  94. ephRequest.Post.UserId = c.App.Session().UserId
  95. ephRequest.Post.CreateAt = model.GetMillis()
  96. if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_CREATE_POST_EPHEMERAL) {
  97. c.SetPermissionError(model.PERMISSION_CREATE_POST_EPHEMERAL)
  98. return
  99. }
  100. rp := c.App.SendEphemeralPost(ephRequest.UserID, c.App.PostWithProxyRemovedFromImageURLs(ephRequest.Post))
  101. w.WriteHeader(http.StatusCreated)
  102. rp = model.AddPostActionCookies(rp, c.App.PostActionCookieSecret())
  103. rp = c.App.PreparePostForClient(rp, true, false)
  104. w.Write([]byte(rp.ToJson()))
  105. }
  106. func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
  107. c.RequireChannelId()
  108. if c.Err != nil {
  109. return
  110. }
  111. afterPost := r.URL.Query().Get("after")
  112. if len(afterPost) > 0 && !model.IsValidId(afterPost) {
  113. c.SetInvalidParam("after")
  114. return
  115. }
  116. beforePost := r.URL.Query().Get("before")
  117. if len(beforePost) > 0 && !model.IsValidId(beforePost) {
  118. c.SetInvalidParam("before")
  119. return
  120. }
  121. sinceString := r.URL.Query().Get("since")
  122. var since int64
  123. var parseError error
  124. if len(sinceString) > 0 {
  125. since, parseError = strconv.ParseInt(sinceString, 10, 64)
  126. if parseError != nil {
  127. c.SetInvalidParam("since")
  128. return
  129. }
  130. }
  131. skipFetchThreads := r.URL.Query().Get("skipFetchThreads") == "true"
  132. channelId := c.Params.ChannelId
  133. page := c.Params.Page
  134. perPage := c.Params.PerPage
  135. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), channelId, model.PERMISSION_READ_CHANNEL) {
  136. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  137. return
  138. }
  139. var list *model.PostList
  140. var err *model.AppError
  141. etag := ""
  142. if since > 0 {
  143. list, err = c.App.GetPostsSince(model.GetPostsSinceOptions{ChannelId: channelId, Time: since, SkipFetchThreads: skipFetchThreads})
  144. } else if len(afterPost) > 0 {
  145. etag = c.App.GetPostsEtag(channelId)
  146. if c.HandleEtag(etag, "Get Posts After", w, r) {
  147. return
  148. }
  149. list, err = c.App.GetPostsAfterPost(model.GetPostsOptions{ChannelId: channelId, PostId: afterPost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads})
  150. } else if len(beforePost) > 0 {
  151. etag = c.App.GetPostsEtag(channelId)
  152. if c.HandleEtag(etag, "Get Posts Before", w, r) {
  153. return
  154. }
  155. list, err = c.App.GetPostsBeforePost(model.GetPostsOptions{ChannelId: channelId, PostId: beforePost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads})
  156. } else {
  157. etag = c.App.GetPostsEtag(channelId)
  158. if c.HandleEtag(etag, "Get Posts", w, r) {
  159. return
  160. }
  161. list, err = c.App.GetPostsPage(model.GetPostsOptions{ChannelId: channelId, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads})
  162. }
  163. if err != nil {
  164. c.Err = err
  165. return
  166. }
  167. if len(etag) > 0 {
  168. w.Header().Set(model.HEADER_ETAG_SERVER, etag)
  169. }
  170. c.App.AddCursorIdsForPostList(list, afterPost, beforePost, since, page, perPage)
  171. clientPostList := c.App.PreparePostListForClient(list)
  172. w.Write([]byte(clientPostList.ToJson()))
  173. }
  174. func getPostsForChannelAroundLastUnread(c *Context, w http.ResponseWriter, r *http.Request) {
  175. c.RequireUserId().RequireChannelId()
  176. if c.Err != nil {
  177. return
  178. }
  179. userId := c.Params.UserId
  180. if !c.App.SessionHasPermissionToUser(*c.App.Session(), userId) {
  181. c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
  182. return
  183. }
  184. channelId := c.Params.ChannelId
  185. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), channelId, model.PERMISSION_READ_CHANNEL) {
  186. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  187. return
  188. }
  189. if c.Params.LimitAfter == 0 {
  190. c.SetInvalidUrlParam("limit_after")
  191. return
  192. }
  193. skipFetchThreads := r.URL.Query().Get("skipFetchThreads") == "true"
  194. postList, err := c.App.GetPostsForChannelAroundLastUnread(channelId, userId, c.Params.LimitBefore, c.Params.LimitAfter, skipFetchThreads)
  195. if err != nil {
  196. c.Err = err
  197. return
  198. }
  199. etag := ""
  200. if len(postList.Order) == 0 {
  201. etag = c.App.GetPostsEtag(channelId)
  202. if c.HandleEtag(etag, "Get Posts", w, r) {
  203. return
  204. }
  205. postList, err = c.App.GetPostsPage(model.GetPostsOptions{ChannelId: channelId, Page: app.PAGE_DEFAULT, PerPage: c.Params.LimitBefore, SkipFetchThreads: skipFetchThreads})
  206. if err != nil {
  207. c.Err = err
  208. return
  209. }
  210. }
  211. postList.NextPostId = c.App.GetNextPostIdFromPostList(postList)
  212. postList.PrevPostId = c.App.GetPrevPostIdFromPostList(postList)
  213. clientPostList := c.App.PreparePostListForClient(postList)
  214. if len(etag) > 0 {
  215. w.Header().Set(model.HEADER_ETAG_SERVER, etag)
  216. }
  217. w.Write([]byte(clientPostList.ToJson()))
  218. }
  219. func getFlaggedPostsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
  220. c.RequireUserId()
  221. if c.Err != nil {
  222. return
  223. }
  224. if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
  225. c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
  226. return
  227. }
  228. channelId := r.URL.Query().Get("channel_id")
  229. teamId := r.URL.Query().Get("team_id")
  230. var posts *model.PostList
  231. var err *model.AppError
  232. if len(channelId) > 0 {
  233. posts, err = c.App.GetFlaggedPostsForChannel(c.Params.UserId, channelId, c.Params.Page, c.Params.PerPage)
  234. } else if len(teamId) > 0 {
  235. posts, err = c.App.GetFlaggedPostsForTeam(c.Params.UserId, teamId, c.Params.Page, c.Params.PerPage)
  236. } else {
  237. posts, err = c.App.GetFlaggedPosts(c.Params.UserId, c.Params.Page, c.Params.PerPage)
  238. }
  239. pl := model.NewPostList()
  240. channelReadPermission := make(map[string]bool)
  241. for _, post := range posts.Posts {
  242. allowed, ok := channelReadPermission[post.ChannelId]
  243. if !ok {
  244. allowed = false
  245. if c.App.SessionHasPermissionToChannel(*c.App.Session(), post.ChannelId, model.PERMISSION_READ_CHANNEL) {
  246. allowed = true
  247. }
  248. channelReadPermission[post.ChannelId] = allowed
  249. }
  250. if !allowed {
  251. continue
  252. }
  253. pl.AddPost(post)
  254. pl.AddOrder(post.Id)
  255. }
  256. pl.SortByCreateAt()
  257. if err != nil {
  258. c.Err = err
  259. return
  260. }
  261. w.Write([]byte(c.App.PreparePostListForClient(pl).ToJson()))
  262. }
  263. func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
  264. c.RequirePostId()
  265. if c.Err != nil {
  266. return
  267. }
  268. post, err := c.App.GetSinglePost(c.Params.PostId)
  269. if err != nil {
  270. c.Err = err
  271. return
  272. }
  273. channel, err := c.App.GetChannel(post.ChannelId)
  274. if err != nil {
  275. c.Err = err
  276. return
  277. }
  278. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), channel.Id, model.PERMISSION_READ_CHANNEL) {
  279. if channel.Type == model.CHANNEL_OPEN {
  280. if !c.App.SessionHasPermissionToTeam(*c.App.Session(), channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
  281. c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
  282. return
  283. }
  284. } else {
  285. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  286. return
  287. }
  288. }
  289. post = c.App.PreparePostForClient(post, false, false)
  290. if c.HandleEtag(post.Etag(), "Get Post", w, r) {
  291. return
  292. }
  293. w.Header().Set(model.HEADER_ETAG_SERVER, post.Etag())
  294. w.Write([]byte(post.ToJson()))
  295. }
  296. func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
  297. c.RequirePostId()
  298. if c.Err != nil {
  299. return
  300. }
  301. auditRec := c.MakeAuditRecord("deletePost", audit.Fail)
  302. defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
  303. auditRec.AddMeta("post_id", c.Params.PostId)
  304. post, err := c.App.GetSinglePost(c.Params.PostId)
  305. if err != nil {
  306. c.SetPermissionError(model.PERMISSION_DELETE_POST)
  307. return
  308. }
  309. auditRec.AddMeta("post", post)
  310. if c.App.Session().UserId == post.UserId {
  311. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), post.ChannelId, model.PERMISSION_DELETE_POST) {
  312. c.SetPermissionError(model.PERMISSION_DELETE_POST)
  313. return
  314. }
  315. } else {
  316. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), post.ChannelId, model.PERMISSION_DELETE_OTHERS_POSTS) {
  317. c.SetPermissionError(model.PERMISSION_DELETE_OTHERS_POSTS)
  318. return
  319. }
  320. }
  321. if _, err := c.App.DeletePost(c.Params.PostId, c.App.Session().UserId); err != nil {
  322. c.Err = err
  323. return
  324. }
  325. auditRec.Success()
  326. ReturnStatusOK(w)
  327. }
  328. func getPostThread(c *Context, w http.ResponseWriter, r *http.Request) {
  329. c.RequirePostId()
  330. if c.Err != nil {
  331. return
  332. }
  333. skipFetchThreads := r.URL.Query().Get("skipFetchThreads") == "true"
  334. list, err := c.App.GetPostThread(c.Params.PostId, skipFetchThreads)
  335. if err != nil {
  336. c.Err = err
  337. return
  338. }
  339. post, ok := list.Posts[c.Params.PostId]
  340. if !ok {
  341. c.SetInvalidUrlParam("post_id")
  342. return
  343. }
  344. channel, err := c.App.GetChannel(post.ChannelId)
  345. if err != nil {
  346. c.Err = err
  347. return
  348. }
  349. if !c.App.SessionHasPermissionToChannel(*c.App.Session(), channel.Id, model.PERMISSION_READ_CHANNEL) {
  350. if channel.Type == model.CHANNEL_OPEN {
  351. if !c.App.SessionHasPermissionToTeam(*c.App.Session(), channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
  352. c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
  353. return
  354. }
  355. } else {
  356. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  357. return
  358. }
  359. }
  360. if c.HandleEtag(list.Etag(), "Get Post Thread", w, r) {
  361. return
  362. }
  363. clientPostList := c.App.PreparePostListForClient(list)
  364. w.Header().Set(model.HEADER_ETAG_SERVER, clientPostList.Etag())
  365. w.Write([]byte(clientPostList.ToJson()))
  366. }
  367. func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
  368. c.RequireTeamId()
  369. if c.Err != nil {
  370. return
  371. }
  372. if !c.App.SessionHasPermissionToTeam(*c.App.Session(), c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
  373. c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
  374. return
  375. }
  376. params := model.SearchParameterFromJson(r.Body)
  377. if params.Terms == nil || len(*params.Terms) == 0 {
  378. c.SetInvalidParam("terms")
  379. return
  380. }
  381. terms := *params.Terms
  382. timeZoneOffset := 0
  383. if params.TimeZoneOffset != nil {
  384. timeZoneOffset = *params.TimeZoneOffset
  385. }
  386. isOrSearch := false
  387. if params.IsOrSearch != nil {
  388. isOrSearch = *params.IsOrSearch
  389. }
  390. page := 0
  391. if params.Page != nil {
  392. page = *params.Page
  393. }
  394. perPage := 60
  395. if params.PerPage != nil {
  396. perPage = *params.PerPage
  397. }
  398. includeDeletedChannels := false
  399. if params.IncludeDeletedChannels != nil {
  400. includeDeletedChannels = *params.IncludeDeletedChannels
  401. }
  402. startTime := time.Now()
  403. results, err := c.App.SearchPostsInTeamForUser(terms, c.App.Session().UserId, c.Params.TeamId, isOrSearch, includeDeletedChannels, timeZoneOffset, page, perPage)
  404. elapsedTime := float64(time.Since(startTime)) / float64(time.Second)
  405. metrics := c.App.Metrics()
  406. if metrics != nil {
  407. metrics.IncrementPostsSearchCounter()
  408. metrics.ObservePostsSearchDuration(elapsedTime)
  409. }
  410. if err != nil {
  411. c.Err = err
  412. return
  413. }
  414. clientPostList := c.App.PreparePostListForClient(results.PostList)
  415. results = model.MakePostSearchResults(clientPostList, results.Matches)
  416. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  417. w.Write([]byte(results.ToJson()))
  418. }
  419. func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
  420. c.RequirePostId()
  421. if c.Err != nil {
  422. return
  423. }
  424. post := model.PostFromJson(r.Body)
  425. if post == nil {
  426. c.SetInvalidParam("post")
  427. return
  428. }
  429. auditRec := c.MakeAuditRecord("updatePost", audit.Fail)
  430. defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
  431. // The post being updated in the payload must be the same one as indicated in the URL.
  432. if post.Id != c.Params.PostId {
  433. c.SetInvalidParam("id")
  434. return
  435. }
  436. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, model.PERMISSION_EDIT_POST) {
  437. c.SetPermissionError(model.PERMISSION_EDIT_POST)
  438. return
  439. }
  440. originalPost, err := c.App.GetSinglePost(c.Params.PostId)
  441. if err != nil {
  442. c.SetPermissionError(model.PERMISSION_EDIT_POST)
  443. return
  444. }
  445. auditRec.AddMeta("post", originalPost)
  446. // Updating the file_ids of a post is not a supported operation and will be ignored
  447. post.FileIds = originalPost.FileIds
  448. if c.App.Session().UserId != originalPost.UserId {
  449. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, model.PERMISSION_EDIT_OTHERS_POSTS) {
  450. c.SetPermissionError(model.PERMISSION_EDIT_OTHERS_POSTS)
  451. return
  452. }
  453. }
  454. post.Id = c.Params.PostId
  455. rpost, err := c.App.UpdatePost(c.App.PostWithProxyRemovedFromImageURLs(post), false)
  456. if err != nil {
  457. c.Err = err
  458. return
  459. }
  460. auditRec.Success()
  461. auditRec.AddMeta("update", rpost)
  462. w.Write([]byte(rpost.ToJson()))
  463. }
  464. func patchPost(c *Context, w http.ResponseWriter, r *http.Request) {
  465. c.RequirePostId()
  466. if c.Err != nil {
  467. return
  468. }
  469. post := model.PostPatchFromJson(r.Body)
  470. if post == nil {
  471. c.SetInvalidParam("post")
  472. return
  473. }
  474. auditRec := c.MakeAuditRecord("patchPost", audit.Fail)
  475. defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
  476. // Updating the file_ids of a post is not a supported operation and will be ignored
  477. post.FileIds = nil
  478. originalPost, err := c.App.GetSinglePost(c.Params.PostId)
  479. if err != nil {
  480. c.SetPermissionError(model.PERMISSION_EDIT_POST)
  481. return
  482. }
  483. auditRec.AddMeta("post", originalPost)
  484. var permission *model.Permission
  485. if c.App.Session().UserId == originalPost.UserId {
  486. permission = model.PERMISSION_EDIT_POST
  487. } else {
  488. permission = model.PERMISSION_EDIT_OTHERS_POSTS
  489. }
  490. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, permission) {
  491. c.SetPermissionError(permission)
  492. return
  493. }
  494. patchedPost, err := c.App.PatchPost(c.Params.PostId, c.App.PostPatchWithProxyRemovedFromImageURLs(post))
  495. if err != nil {
  496. c.Err = err
  497. return
  498. }
  499. auditRec.Success()
  500. auditRec.AddMeta("patch", patchedPost)
  501. w.Write([]byte(patchedPost.ToJson()))
  502. }
  503. func setPostUnread(c *Context, w http.ResponseWriter, r *http.Request) {
  504. c.RequirePostId().RequireUserId()
  505. if c.Err != nil {
  506. return
  507. }
  508. if c.App.Session().UserId != c.Params.UserId && !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
  509. c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
  510. return
  511. }
  512. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
  513. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  514. return
  515. }
  516. state, err := c.App.MarkChannelAsUnreadFromPost(c.Params.PostId, c.Params.UserId)
  517. if err != nil {
  518. c.Err = err
  519. return
  520. }
  521. w.Write([]byte(state.ToJson()))
  522. }
  523. func saveIsPinnedPost(c *Context, w http.ResponseWriter, r *http.Request, isPinned bool) {
  524. c.RequirePostId()
  525. if c.Err != nil {
  526. return
  527. }
  528. auditRec := c.MakeAuditRecord("saveIsPinnedPost", audit.Fail)
  529. defer c.LogAuditRecWithLevel(auditRec, app.LevelContent)
  530. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
  531. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  532. return
  533. }
  534. // Restrict pinning if the experimental read-only-town-square setting is on.
  535. user, err := c.App.GetUser(c.App.Session().UserId)
  536. if err != nil {
  537. c.Err = err
  538. return
  539. }
  540. post, err := c.App.GetSinglePost(c.Params.PostId)
  541. if err != nil {
  542. c.Err = err
  543. return
  544. }
  545. auditRec.AddMeta("post", post)
  546. channel, err := c.App.GetChannel(post.ChannelId)
  547. if err != nil {
  548. c.Err = err
  549. return
  550. }
  551. if c.App.Srv().License() != nil &&
  552. *c.App.Config().TeamSettings.ExperimentalTownSquareIsReadOnly &&
  553. channel.Name == model.DEFAULT_CHANNEL &&
  554. !c.App.RolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) {
  555. c.Err = model.NewAppError("saveIsPinnedPost", "api.post.save_is_pinned_post.town_square_read_only", nil, "", http.StatusForbidden)
  556. return
  557. }
  558. patch := &model.PostPatch{}
  559. patch.IsPinned = model.NewBool(isPinned)
  560. patchedPost, err := c.App.PatchPost(c.Params.PostId, patch)
  561. if err != nil {
  562. c.Err = err
  563. return
  564. }
  565. auditRec.AddMeta("patch", patchedPost)
  566. auditRec.Success()
  567. ReturnStatusOK(w)
  568. }
  569. func pinPost(c *Context, w http.ResponseWriter, r *http.Request) {
  570. saveIsPinnedPost(c, w, r, true)
  571. }
  572. func unpinPost(c *Context, w http.ResponseWriter, r *http.Request) {
  573. saveIsPinnedPost(c, w, r, false)
  574. }
  575. func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
  576. c.RequirePostId()
  577. if c.Err != nil {
  578. return
  579. }
  580. if !c.App.SessionHasPermissionToChannelByPost(*c.App.Session(), c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
  581. c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
  582. return
  583. }
  584. infos, err := c.App.GetFileInfosForPostWithMigration(c.Params.PostId)
  585. if err != nil {
  586. c.Err = err
  587. return
  588. }
  589. if c.HandleEtag(model.GetEtagForFileInfos(infos), "Get File Infos For Post", w, r) {
  590. return
  591. }
  592. w.Header().Set("Cache-Control", "max-age=2592000, public")
  593. w.Header().Set(model.HEADER_ETAG_SERVER, model.GetEtagForFileInfos(infos))
  594. w.Write([]byte(model.FileInfosToJson(infos)))
  595. }