mattermost/api/v4/source/posts.yaml

1451 lines
45 KiB
YAML
Raw Permalink Normal View History

/api/v4/posts:
post:
tags:
- posts
summary: Create a post
description: >
Create a new post in a channel. To create the post as a comment on
another post, provide `root_id`.
##### Permissions
Must have `create_post` permission for the channel the post is being created in.
operationId: CreatePost
parameters:
- name: set_online
in: query
description: Whether to set the user status as online or not.
required: false
schema:
type: boolean
requestBody:
content:
application/json:
schema:
type: object
required:
- channel_id
- message
properties:
channel_id:
type: string
description: The channel ID to post in
message:
type: string
description: The message contents, can be formatted with Markdown
root_id:
type: string
description: The post ID to comment on
file_ids:
type: array
description: A list of file IDs to associate with the post. Note that
posts are limited to 5 files maximum. Please use additional
posts for more files.
items:
type: string
props:
description: A general JSON property bag to attach to the post
type: object
metadata:
description: A JSON object to add post metadata, e.g the post's priority
type: object
properties:
priority:
type: object
description: An object containing the post's priority properties
properties:
priority:
type: string
description: The priority label of the post, could empty, important, or urgent
requested_ack:
type: boolean
description: Set to true to request for acknowledgements
description: Post object to create
required: true
responses:
"201":
description: Post creation successful
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v4/posts/ephemeral:
post:
tags:
- posts
summary: Create a ephemeral post
description: >
Create a new ephemeral post in a channel.
##### Permissions
Must have `create_post_ephemeral` permission (currently only given to system admin)
operationId: CreatePostEphemeral
requestBody:
content:
application/json:
schema:
type: object
required:
- user_id
- post
properties:
user_id:
type: string
description: The target user id for the ephemeral post
post:
type: object
required:
- channel_id
- message
description: Post object to create
properties:
channel_id:
type: string
description: The channel ID to post in
message:
type: string
description: The message contents, can be formatted with Markdown
description: Ephemeral Post object to send
required: true
responses:
"201":
description: Post creation successful
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v4/posts/search:
post:
tags:
- posts
summary: Search posts across all teams
description: |
Search posts visible to the current user across all teams.
##### Permissions
Must be authenticated.
operationId: SearchPostsInAllTeams
requestBody:
content:
application/json:
schema:
type: object
required:
- terms
properties:
terms:
type: string
is_or_search:
type: boolean
time_zone_offset:
type: integer
include_deleted_channels:
type: boolean
page:
type: integer
per_page:
type: integer
required: true
responses:
"200":
description: Post search successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostListWithSearchMatches"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}":
get:
tags:
- posts
summary: Get a post
description: >
Get a single post.
##### Permissions
Must have `read_channel` permission for the channel the post is in or if the channel is public, have the `read_public_channels` permission for the team.
operationId: GetPost
parameters:
- name: post_id
in: path
description: ID of the post to get
required: true
schema:
type: string
- name: include_deleted
in: query
description: Defines if result should include deleted posts, must have 'manage_system' (admin) permission.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: Post retrieval successful
headers:
Has-Inaccessible-Posts:
schema:
type: boolean
description: This header is included with the value "true" if the post is past the cloud's plan limit.
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
delete:
tags:
- posts
summary: Delete a post
description: >
Soft deletes a post, by marking the post as deleted in the database.
Soft deleted posts will not be returned in post queries.
##### Permissions
Must be logged in as the user or have `delete_others_posts` permission.
operationId: DeletePost
parameters:
- name: post_id
in: path
description: ID of the post to delete
required: true
schema:
type: string
responses:
"200":
description: Post deletion successful
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
put:
tags:
- posts
summary: Update a post
description: >
Update a post. Only the fields listed below are updatable, omitted
fields will be treated as blank.
##### Permissions
Must have `edit_post` permission for the channel the post is in.
operationId: UpdatePost
parameters:
- name: post_id
in: path
description: ID of the post to update
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- id
properties:
id:
description: ID of the post to update
type: string
is_pinned:
description: Set to `true` to pin the post to the channel it is in
type: boolean
message:
description: The message text of the post
type: string
has_reactions:
description: Set to `true` if the post has reactions to it
type: boolean
props:
description: A general JSON property bag to attach to the post
type: string
description: Post object that is to be updated
required: true
responses:
"200":
description: Post update successful
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/users/{user_id}/posts/{post_id}/set_unread":
post:
tags:
- posts
summary: Mark as unread from a post.
description: >
Mark a channel as being unread from a given post.
##### Permissions
Must have `read_channel` permission for the channel the post is in or if the channel is public, have the `read_public_channels` permission for the team.
Must have `edit_other_users` permission if the user is not the one marking the post for himself.
__Minimum server version__: 5.18
operationId: SetPostUnread
parameters:
- name: user_id
in: path
description: User GUID
required: true
schema:
type: string
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
responses:
"200":
description: Post marked as unread successfully
content:
application/json:
schema:
$ref: "#/components/schemas/ChannelUnreadAt"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"/api/v4/posts/{post_id}/patch":
put:
tags:
- posts
summary: Patch a post
description: >
Partially update a post by providing only the fields you want to update.
Omitted fields will not be updated. The fields that can be updated are
defined in the request body, all other provided fields will be ignored.
##### Permissions
Must have the `edit_post` permission.
operationId: PatchPost
parameters:
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
is_pinned:
description: Set to `true` to pin the post to the channel it is in
type: boolean
message:
description: The message text of the post
type: string
file_ids:
description: The list of files attached to this post
type: array
items:
type: string
has_reactions:
description: Set to `true` if the post has reactions to it
type: boolean
props:
description: A general JSON property bag to attach to the post
type: string
description: Post object that is to be updated
required: true
responses:
"200":
description: Post patch successful
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/thread":
get:
tags:
- posts
summary: Get a thread
description: >
Get a post and the rest of the posts in the same thread.
##### Permissions
Must have `read_channel` permission for the channel the post is in or if the channel is public, have the `read_public_channels` permission for the team.
operationId: GetPostThread
parameters:
- name: post_id
in: path
description: ID of a post in the thread
required: true
schema:
type: string
- name: perPage
in: query
description: The number of posts per page
schema:
type: integer
default: 0
- name: fromPost
in: query
description: The post_id to return the next page of posts from
schema:
type: string
default: ""
- name: fromCreateAt
in: query
description: The create_at timestamp to return the next page of posts from
schema:
type: integer
default: 0
MM-56548: [AI assisted]Add support for incremental thread loading using UpdateAt timestamp (#30486) Every time we load the RHS, we used to load the FULL thread always. Although the actual ThreadViewer React component is virtualized, and the server side API call is paginated, we still went through all the pages, to get the full thread and passed it on to the ThreadViewer. This would be for first loads, and subsequent loads of the same thread. This was a bug originally, but then it was a necessity after we applied websocket event scope because now we won't get emoji reactions of a thread if the user is not on the thread. To fix that, we enhance the thread loading functionality by adding support for fetching thread updates based on the UpdateAt timestamp. Now, for subsequent loads, we only get the changed posts in a thread. The implementation: - Adds new API parameters: fromUpdateAt and updatesOnly to the GetPostThread endpoint - Updates database queries to support sorting and filtering by UpdateAt - Implements thread state management to track the last update timestamp - Adds client-side support to use incremental loading for improved performance - Ensures proper validation for parameter combinations and error handling This change enables more efficient thread loading, particularly for long threads with frequent updates, by only fetching posts that have been updated since the last view. Caveats: For delta updates, the SQL query won't use the best index possible because we have an index for (CreateAt, Id), but no index for (UpdateAt, Id). However, from my tests, it is not as bad as it looks: ``` [loadtest] # EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM Posts WHERE Posts.DeleteAt = 0 AND Posts.RootId = 'qbr5gctu9iyg8c36hpcq6f3w8e' AND Posts.UpdateAt > 1623445795824 ORDER BY UpdateAt ASC, Id ASC LIMIT 61; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=8.31..8.31 rows=1 width=216) (actual time=0.047..0.049 rows=0 loops=1) Buffers: shared hit=2 -> Sort (cost=8.31..8.31 rows=1 width=216) (actual time=0.044..0.045 rows=0 loops=1) Sort Key: updateat, id Sort Method: quicksort Memory: 25kB Buffers: shared hit=2 -> Index Scan using idx_posts_root_id_delete_at on posts (cost=0.28..8.30 rows=1 width=216) (actual time=0.031..0.032 rows=0 loops=1) Index Cond: (((rootid)::text = 'qbr5gctu9iyg8c36hpcq6f3w8e'::text) AND (deleteat = 0)) Filter: (updateat > '1623445795824'::bigint) Buffers: shared hit=2 Planning: Buffers: shared hit=3 Planning Time: 0.508 ms Execution Time: 0.106 ms (14 rows) ``` We still get an index scan with index cond. Although there's a filter element, but atleast we get the whole thread with the index. My thinking is that while the whole thread might be large, but after that, updates on a thread should be incremental. Therefore, we should be okay without adding yet another index on the posts table. This is just the first step in what could be potentially improved further. 1. We shouldn't even be loading the full thread always. But rather let the virtualized viewer load more posts on demand. 2. If a post has been just reacted to, then we need not send the whole post down, but just the reaction. This further saves bandwidth. https://mattermost.atlassian.net/browse/MM-56548 TBD: Add load-test coverage to update the thread loading code ```release-note NONE ``` --------- Co-authored-by: Mattermost Build <build@mattermost.com>
2025-04-22 01:13:13 -04:00
- name: fromUpdateAt
in: query
description: The update_at timestamp to return the next page of posts from. You cannot set this flag with direction=down.
schema:
type: integer
default: 0
- name: direction
in: query
description: The direction to return the posts. Either up or down.
schema:
type: string
default: ""
- name: skipFetchThreads
in: query
description: Whether to skip fetching threads or not
schema:
type: boolean
default: false
- name: collapsedThreads
in: query
description: Whether the client uses CRT or not
schema:
type: boolean
default: false
- name: collapsedThreadsExtended
in: query
description: Whether to return the associated users as part of the response or not
schema:
type: boolean
default: false
MM-56548: [AI assisted]Add support for incremental thread loading using UpdateAt timestamp (#30486) Every time we load the RHS, we used to load the FULL thread always. Although the actual ThreadViewer React component is virtualized, and the server side API call is paginated, we still went through all the pages, to get the full thread and passed it on to the ThreadViewer. This would be for first loads, and subsequent loads of the same thread. This was a bug originally, but then it was a necessity after we applied websocket event scope because now we won't get emoji reactions of a thread if the user is not on the thread. To fix that, we enhance the thread loading functionality by adding support for fetching thread updates based on the UpdateAt timestamp. Now, for subsequent loads, we only get the changed posts in a thread. The implementation: - Adds new API parameters: fromUpdateAt and updatesOnly to the GetPostThread endpoint - Updates database queries to support sorting and filtering by UpdateAt - Implements thread state management to track the last update timestamp - Adds client-side support to use incremental loading for improved performance - Ensures proper validation for parameter combinations and error handling This change enables more efficient thread loading, particularly for long threads with frequent updates, by only fetching posts that have been updated since the last view. Caveats: For delta updates, the SQL query won't use the best index possible because we have an index for (CreateAt, Id), but no index for (UpdateAt, Id). However, from my tests, it is not as bad as it looks: ``` [loadtest] # EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM Posts WHERE Posts.DeleteAt = 0 AND Posts.RootId = 'qbr5gctu9iyg8c36hpcq6f3w8e' AND Posts.UpdateAt > 1623445795824 ORDER BY UpdateAt ASC, Id ASC LIMIT 61; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=8.31..8.31 rows=1 width=216) (actual time=0.047..0.049 rows=0 loops=1) Buffers: shared hit=2 -> Sort (cost=8.31..8.31 rows=1 width=216) (actual time=0.044..0.045 rows=0 loops=1) Sort Key: updateat, id Sort Method: quicksort Memory: 25kB Buffers: shared hit=2 -> Index Scan using idx_posts_root_id_delete_at on posts (cost=0.28..8.30 rows=1 width=216) (actual time=0.031..0.032 rows=0 loops=1) Index Cond: (((rootid)::text = 'qbr5gctu9iyg8c36hpcq6f3w8e'::text) AND (deleteat = 0)) Filter: (updateat > '1623445795824'::bigint) Buffers: shared hit=2 Planning: Buffers: shared hit=3 Planning Time: 0.508 ms Execution Time: 0.106 ms (14 rows) ``` We still get an index scan with index cond. Although there's a filter element, but atleast we get the whole thread with the index. My thinking is that while the whole thread might be large, but after that, updates on a thread should be incremental. Therefore, we should be okay without adding yet another index on the posts table. This is just the first step in what could be potentially improved further. 1. We shouldn't even be loading the full thread always. But rather let the virtualized viewer load more posts on demand. 2. If a post has been just reacted to, then we need not send the whole post down, but just the reaction. This further saves bandwidth. https://mattermost.atlassian.net/browse/MM-56548 TBD: Add load-test coverage to update the thread loading code ```release-note NONE ``` --------- Co-authored-by: Mattermost Build <build@mattermost.com>
2025-04-22 01:13:13 -04:00
- name: updatesOnly
in: query
description: This flag is used to make the API work with the updateAt value. If you set this flag, you must set a value for fromUpdateAt.
schema:
type: boolean
default: false
responses:
"200":
description: Post list retrieval successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostList"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/users/{user_id}/posts/flagged":
get:
tags:
- posts
summary: Get a list of flagged posts
description: >
Get a page of flagged posts of a user provided user id string. Selects
from a channel, team, or all flagged posts by a user. Will only return
posts from channels in which the user is member.
##### Permissions
Must be user or have `manage_system` permission.
operationId: GetFlaggedPostsForUser
parameters:
- name: user_id
in: path
description: ID of the user
required: true
schema:
type: string
- name: team_id
in: query
description: Team ID
schema:
type: string
- name: channel_id
in: query
description: Channel ID
schema:
type: string
- name: page
in: query
description: The page to select
schema:
type: integer
default: 0
- name: per_page
in: query
description: The number of posts per page
schema:
type: integer
default: 60
responses:
"200":
description: Post list retrieval successful
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/PostList"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/files/info":
get:
tags:
- posts
summary: Get file info for post
description: >
Gets a list of file information objects for the files attached to a
post.
##### Permissions
Must have `read_channel` permission for the channel the post is in.
operationId: GetFileInfosForPost
parameters:
- name: post_id
in: path
description: ID of the post
required: true
schema:
type: string
- name: include_deleted
in: query
description: Defines if result should include deleted posts, must have 'manage_system' (admin) permission.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: File info retrieval successful
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/FileInfo"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/info":
get:
tags:
- posts
summary: Get post info
description: |
Get additional metadata and access information for a post.
##### Permissions
Must be able to access the post's team and channel context.
operationId: GetPostInfo
parameters:
- name: post_id
in: path
description: Post ID
required: true
schema:
type: string
responses:
"200":
description: Post info retrieval successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostInfo"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"/api/v4/posts/{post_id}/edit_history":
get:
tags:
- posts
summary: Get post edit history
description: |
Get edit history entries for a post.
##### Permissions
Must have `edit_post` permission in the channel. For most posts, only the original author can access history.
operationId: GetEditHistoryForPost
parameters:
- name: post_id
in: path
description: Post ID
required: true
schema:
type: string
responses:
"200":
description: Edit history retrieval successful
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"/api/v4/channels/{channel_id}/posts":
get:
tags:
- posts
summary: Get posts for a channel
description: >
Get a page of posts in a channel. Use the query parameters to modify the
behaviour of this endpoint. The parameter `since` must not be used with any of
`before`, `after`, `page`, and `per_page` parameters.
If `since` is used, it will always return all posts modified since that time,
ordered by their create time limited till 1000. A caveat with this parameter is that
there is no guarantee that the returned posts will be consecutive. It is left to the clients
to maintain state and fill any missing holes in the post order.
##### Permissions
Must have `read_channel` permission for the channel.
operationId: GetPostsForChannel
parameters:
- name: channel_id
in: path
description: The channel ID to get the posts for
required: true
schema:
type: string
- name: page
in: query
description: The page to select
schema:
type: integer
default: 0
- name: per_page
in: query
description: The number of posts per page
schema:
type: integer
default: 60
- name: since
in: query
description: Provide a non-zero value in Unix time milliseconds to select posts
modified after that time
schema:
type: integer
- name: before
in: query
description: A post id to select the posts that came before this one
schema:
type: string
- name: after
in: query
description: A post id to select the posts that came after this one
schema:
type: string
- name: include_deleted
in: query
description: Whether to include deleted posts or not. Must have system admin permissions.
schema:
type: boolean
default: false
Merge the Integrated Boards MVP feature branch (#35796) * Add CreatedBy and UpdatedBy to the properties fields and values (#34485) * Add CreatedBy and UpdatedBy to the properties fields and values * Fix types --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Adds ObjectType to the property fields table (#34908) Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Update ObjectType migration setting an empty value and marking the column as not null (#34915) Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Adds uniqueness mechanisms to the property fields (#35058) * Adds uniqueness mechanisms to the property fields After adding ObjectType, this commit ensures that both the PSAv1 and PSAv2 schemas are supported, and enforces property uniqueness through both database indexes and a logical check when creating new property fields. * Adds uniqueness check to property updates Updates are covered on this commit and we refactor as well the SQL code to use the squirrel builder and work better with the conditional addition of the `existingID` piece of the query. * Add translations to error messages * Fixing retrylayer mocks * Remove retrylayer duplication * Address review comments * Fix comment to avoid linter issues * Address PR comments * Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.down.sql Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.up.sql Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * Update server/channels/db/migrations/postgres/000157_add_object_type_to_property_fields.up.sql Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * Update field validation to check only for valid target types * Update migrations to avoid concurrent index creation within a transaction * Update migrations to make all index ops concurrent * Update tests to use valid PSAv2 property fields * Adds a helper for valid PSAv2 TargetTypes --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * Fix property tests (#35388) Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Adds Integrated Boards feature flag (#35378) Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Adds Integrated Boards MVP API changes (#34822) This PR includes the necessary changes for channels and posts endpoints and adds a set of generic endpoints to retrieve and manage property fields and values following the new Property System approach. Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> Co-authored-by: Mattermost Build <build@mattermost.com> * Property System Architecture permissions for v2 (#35113) * Adds uniqueness mechanisms to the property fields After adding ObjectType, this commit ensures that both the PSAv1 and PSAv2 schemas are supported, and enforces property uniqueness through both database indexes and a logical check when creating new property fields. * Adds uniqueness check to property updates Updates are covered on this commit and we refactor as well the SQL code to use the squirrel builder and work better with the conditional addition of the `existingID` piece of the query. * Add translations to error messages * Add the permissions to the migrations, model and update the store calls * Adds the property field and property group app layer * Adds authorization helpers for property fields and values * Make sure that users cannot lock themselves out of property fields * Migrate permissions from a JSON column to three normalized columns * Remove the audit comment * Use target level constants in authorization * Log authorization membership failures * Rename admin to sysadmin * Fix i18n sorting --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Add Views store and app layer (#35361) * Add Views store and app layer for Integrated Boards Implements the View entity (model, SQL store, service, app) as described in the Integrated Boards tech spec. Views are channel-scoped board configurations with typed props (board, kanban subviews) and soft-delete. - public/model: View, ViewBoardProps, Subview, ViewPatch types with PreSave/PreUpdate/IsValid/Patch/Clone/Auditable - Migration 158: Views table with jsonb Props column and indexes - SqlViewStore: CRUD with nil-safe Props marshaling (AppendBinaryFlag) - ViewService: CreateView seeds default kanban subview and links the boards property field; caches boardPropertyFieldID at startup - App layer: CreateView/GetView/GetViewsForChannel/UpdateView/DeleteView with channel-membership permission checks and WebSocket events (view_created, view_updated, view_deleted) - doSetupBoardsPropertyField: registers the Boards property group and board field in NewServer() before ViewService construction - GetFieldByName now returns store.ErrNotFound instead of raw sql.ErrNoRows * Move permission checks out of App layer for views - Remove HasPermissionToChannel calls from all App view methods - Drop userID params from GetView, GetViewsForChannel, UpdateView, DeleteView - Fix doSetupBoardsPropertyField to include required TargetType for PSAv2 field * Make View service generic and enforce board validation in model - Remove board-specific auto-setup from service and server startup - Enforce that board views require Props, at least one subview, and at least one linked property in IsValid() - Move default subview seeding out of app layer; callers must provide valid props - Call PreSave on subviews during PreUpdate to assign IDs to new subviews - Update all tests to reflect the new validation requirements * Restore migrations files to match base branch * Distinguish ErrNotFound from other errors in view store Get * Use CONCURRENTLY and nontransactional for index operations in views migration * Split views index creation into separate nontransactional migrations * Update migrations.list * Update i18n translations for views * Fix makeView helper to include required Props for board view validation * Rename ctx parameter from c to rctx in OAuthProvider mock * Remove views service layer, call store directly from app * Return 500 for unexpected DB errors in GetView, 404 only for not-found * Harden View model: deep-copy Props, validate linked property IDs - Add ViewBoardProps.Clone() to deep-copy LinkedProperties and Subviews - Use it in View.Clone() and View.Patch() to prevent shared-slice aliasing - Iterate over LinkedProperties in View.IsValid() and reject invalid IDs with a dedicated i18n key - Register ViewStore in storetest AssertExpectations so mock expectations are enforced - Add tests covering all new behaviours * Restore autotranslation worker_stopped i18n translation * Fix view store test IDs and improve error handling in app layer - Use model.NewId() for linked property IDs in testUpdateView to fix validation failure (IsValid rejects non-UUID strings) - Fix import grouping in app/view.go (stdlib imports in one block) - Return 404 instead of 500 when Update/Delete store calls return ErrNotFound (e.g. concurrent deletion TOCTOU race) * Add View store mock to retrylayer test genStore helper The View store was added to the store interface but the genStore() helper in retrylayer_test.go was not updated, causing TestRetry to panic. Also removes the duplicate Recap mock registration. * Refactor view deletion and websocket event handling; update SQL store methods to use query builder * revert property field store * Remove useless migrations * Add cursor-based pagination to View store GetForChannel - Add ViewQueryCursor and ViewQueryOpts types with validation - Return (views, cursor, error) for caller-driven pagination - PerPage clamping: <=0 defaults to 20, >200 clamps to 200 - Support IncludeDeleted filter - Add comprehensive store tests for pagination, cursor edge cases, PerPage clamping, and invalid input rejection - Add app layer test for empty channelID → 400 - Update interface, retrylayer, timerlayer, and mock signatures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor test loops in ViewStore tests for improved readability * change pagination to limit/offset * Add upper-bound limits on View Subviews and LinkedProperties Defense-in-depth validation: cap Subviews at 50 and LinkedProperties at 500 to prevent abuse below the 300KB payload limit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * MM-67388, MM-66528, MM-67750: Add View REST API endpoints, websocket events, and sort order (#35442) * Add Views store and app layer for Integrated Boards Implements the View entity (model, SQL store, service, app) as described in the Integrated Boards tech spec. Views are channel-scoped board configurations with typed props (board, kanban subviews) and soft-delete. - public/model: View, ViewBoardProps, Subview, ViewPatch types with PreSave/PreUpdate/IsValid/Patch/Clone/Auditable - Migration 158: Views table with jsonb Props column and indexes - SqlViewStore: CRUD with nil-safe Props marshaling (AppendBinaryFlag) - ViewService: CreateView seeds default kanban subview and links the boards property field; caches boardPropertyFieldID at startup - App layer: CreateView/GetView/GetViewsForChannel/UpdateView/DeleteView with channel-membership permission checks and WebSocket events (view_created, view_updated, view_deleted) - doSetupBoardsPropertyField: registers the Boards property group and board field in NewServer() before ViewService construction - GetFieldByName now returns store.ErrNotFound instead of raw sql.ErrNoRows * Move permission checks out of App layer for views - Remove HasPermissionToChannel calls from all App view methods - Drop userID params from GetView, GetViewsForChannel, UpdateView, DeleteView - Fix doSetupBoardsPropertyField to include required TargetType for PSAv2 field * Make View service generic and enforce board validation in model - Remove board-specific auto-setup from service and server startup - Enforce that board views require Props, at least one subview, and at least one linked property in IsValid() - Move default subview seeding out of app layer; callers must provide valid props - Call PreSave on subviews during PreUpdate to assign IDs to new subviews - Update all tests to reflect the new validation requirements * Restore migrations files to match base branch * Distinguish ErrNotFound from other errors in view store Get * Use CONCURRENTLY and nontransactional for index operations in views migration * Split views index creation into separate nontransactional migrations * Update migrations.list * Update i18n translations for views * Fix makeView helper to include required Props for board view validation * Rename ctx parameter from c to rctx in OAuthProvider mock * Remove views service layer, call store directly from app * Return 500 for unexpected DB errors in GetView, 404 only for not-found * Harden View model: deep-copy Props, validate linked property IDs - Add ViewBoardProps.Clone() to deep-copy LinkedProperties and Subviews - Use it in View.Clone() and View.Patch() to prevent shared-slice aliasing - Iterate over LinkedProperties in View.IsValid() and reject invalid IDs with a dedicated i18n key - Register ViewStore in storetest AssertExpectations so mock expectations are enforced - Add tests covering all new behaviours * Restore autotranslation worker_stopped i18n translation * Fix view store test IDs and improve error handling in app layer - Use model.NewId() for linked property IDs in testUpdateView to fix validation failure (IsValid rejects non-UUID strings) - Fix import grouping in app/view.go (stdlib imports in one block) - Return 404 instead of 500 when Update/Delete store calls return ErrNotFound (e.g. concurrent deletion TOCTOU race) * Add View store mock to retrylayer test genStore helper The View store was added to the store interface but the genStore() helper in retrylayer_test.go was not updated, causing TestRetry to panic. Also removes the duplicate Recap mock registration. * Refactor view deletion and websocket event handling; update SQL store methods to use query builder * revert property field store * Add View API endpoints with OpenAPI spec, client methods, and i18n Implement REST API for channel views (board-type) behind the IntegratedBoards feature flag. Adds CRUD endpoints under /api/v4/channels/{channel_id}/views with permission checks matching the channel bookmark pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove useless migrations * Add cursor-based pagination to View store GetForChannel - Add ViewQueryCursor and ViewQueryOpts types with validation - Return (views, cursor, error) for caller-driven pagination - PerPage clamping: <=0 defaults to 20, >200 clamps to 200 - Support IncludeDeleted filter - Add comprehensive store tests for pagination, cursor edge cases, PerPage clamping, and invalid input rejection - Add app layer test for empty channelID → 400 - Update interface, retrylayer, timerlayer, and mock signatures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add cursor-based pagination to View API for channel views * Enhance cursor handling in getViewsForChannel and update tests for pagination * Refactor test loops in ViewStore tests for improved readability * Refactor loop in TestGetViewsForChannel for improved readability * change pagination to limit/offset * switch to limit/offset pagination * Add upper-bound limits on View Subviews and LinkedProperties Defense-in-depth validation: cap Subviews at 50 and LinkedProperties at 500 to prevent abuse below the 300KB payload limit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add view sort order API endpoint Add POST /api/v4/channels/{channel_id}/views/{view_id}/sort_order endpoint following the channel bookmarks reorder pattern. Includes store, app, and API layers with full test coverage at each layer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add connectionId to view WebSocket events and sort_order API spec Thread connectionId from request header through all view handlers (create, update, delete, sort_order) to WebSocket events, matching the channel bookmarks pattern. Add sort_order endpoint to OpenAPI spec. Update minimum server version to 11.6. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove duplicate View/ViewPatch definitions from definitions.yaml The merge from integrated-boards-mvp introduced duplicate View and ViewPatch schema definitions that were already defined earlier in the file with more detail (including ViewBoardProps ref and enums). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update minimum server version to 11.6 in views API spec Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add missing translations for view sort order error messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Merge integrated-boards-mvp into ibmvp_api-views; remove spec files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix flaky TestViewStore timestamp test on CI Add sleep before UpdateSortOrder to ensure timestamps differ, preventing same-millisecond comparisons on fast CI machines. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * remove duplicate views.yaml imclude * Use c.boolString() for include_deleted query param in GetViewsForChannel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix views.yaml sort order schema: use integer type and require body Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Refactor view sort order tests to use named IDs instead of array indices Extract idA/idB/idC from views slice and add BEFORE/AFTER comments to make stateful subtest ordering easier to follow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Return 404 instead of 403 for view operations on deleted channels Deleted channels should appear non-existent to callers rather than revealing their existence via a 403. Detailed error text explains the context for debugging. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * add missing channel deleteat checks * Use c.Params.Page instead of manual page query param parsing in getViewsForChannel c.Params already validates and defaults page/per_page, so the manual parsing was redundant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add support for total count in views retrieval * Add tests for handling deleted views in GetViewsForChannel and GetView * Short-circuit negative newIndex in UpdateSortOrder before opening transaction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add per-channel limit on views to bound UpdateSortOrder cost Without a cap, unbounded view creation makes sort-order updates increasingly expensive (CASE WHEN per view, row locks). Adds MaxViewsPerChannel=50 constant and enforces it in the app layer before saving. Includes API and app layer tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove include_deleted support from views API Soft-deleted views are structural metadata with low risk, but no other similar endpoint (e.g. channel bookmarks) exposes deleted records without an admin gate. Rather than adding an admin-only permission check for consistency, remove the feature entirely since there is no current use case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update view permissions to require `create_post` instead of channel management permissions * Remove obsolete view management error messages for direct and group messages --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat(migrations): add user tracking and object type to property fields - Introduced user tracking columns (CreatedBy, UpdatedBy) to PropertyFields and PropertyValues. - Added ObjectType column to PropertyFields with associated unique indexes for legacy and typed properties. - Created new migration scripts for adding and dropping these features, including necessary indexes for data integrity. - Established views for managing property fields with new attributes. This update enhances the schema to support better tracking and categorization of property fields. * Add Property System Architecture v2 API endpoints (#35583) * Adds uniqueness mechanisms to the property fields After adding ObjectType, this commit ensures that both the PSAv1 and PSAv2 schemas are supported, and enforces property uniqueness through both database indexes and a logical check when creating new property fields. * Adds uniqueness check to property updates Updates are covered on this commit and we refactor as well the SQL code to use the squirrel builder and work better with the conditional addition of the `existingID` piece of the query. * Add translations to error messages * Add the permissions to the migrations, model and update the store calls * Adds the property field and property group app layer * Adds authorization helpers for property fields and values * Make sure that users cannot lock themselves out of property fields * Migrate permissions from a JSON column to three normalized columns * Remove the audit comment * Use target level constants in authorization * Log authorization membership failures * Rename admin to sysadmin * Adds the Property System Architecture v2 API endpoints * Adds permission checks to the create field endpoint * Add target access checks to value endpoints * Add default branches for object_type and target_type and extra guards for cursor client4 methods * Fix vet API mismatch * Fix error checks * Fix linter * Add merge semantics for property patch logic and API endpoint * Fix i18n * Fix duplicated patch elements and early return on bad cursor * Update docs to use enums * Fix i18n sorting * Update app layer to return model.AppError * Adds a limit to the number of property values that can be patched in the same request * Require target_type filter when searching property fields * Add objectType validation as part of field.IsValid() * Fix linter * Fix test with bad objecttpye * Fix test grouping --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * MM-67968: Flatten view model — remove icon, subviews, typed board props (#35726) * feat(views): flatten view model by removing icon, subview, and board props Simplifies the View data model as part of MM-67968: removes Icon, Subview, and ViewBoardProps types; renames ViewTypeBoard to ViewTypeKanban; replaces typed Props with StringInterface (map[string]any); adds migration 000167 to drop the Icon column from the Views table. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * feat(api): update views OpenAPI spec to reflect flattened model Removes ViewBoardProps, Subview, and icon from the View and ViewPatch schemas. Changes type enum from board to kanban. Replaces typed props with a free-form StringInterface object. Aligns with MM-67968. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * refactor(views): simplify store by dropping dbView and marshalViewProps StringInterface already implements driver.Valuer and sql.Scanner, so the manual JSON marshal/unmarshal and the dbView intermediate struct were redundant. model.View now scans directly from the database. Also removes the dead ViewMaxLinkedProperties constant and wraps the Commit() error in UpdateSortOrder. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * fix(api): allow arbitrary JSON in view props OpenAPI schema The props field was restricted to string values via additionalProperties: { type: string }, conflicting with the Go model's StringInterface (map[string]any). Changed to additionalProperties: true in View, ViewPatch, and inline POST schemas. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * Adds basic implementation of the generic redux store for PSAv2 (#35512) * Adds basic implementation of the generic redux store for PSAv2 * Add created_by and updated_by to the test fixtures * Make target_id, target_type and object_type mandatory * Wrap getPropertyFieldsByIds and getPropertyValuesForTargetByFieldIds with createSelector * Address PR comments --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * Adds websocket messages for the PSAv2 API events (#35696) * Adds uniqueness mechanisms to the property fields After adding ObjectType, this commit ensures that both the PSAv1 and PSAv2 schemas are supported, and enforces property uniqueness through both database indexes and a logical check when creating new property fields. * Adds uniqueness check to property updates Updates are covered on this commit and we refactor as well the SQL code to use the squirrel builder and work better with the conditional addition of the `existingID` piece of the query. * Add translations to error messages * Add the permissions to the migrations, model and update the store calls * Adds the property field and property group app layer * Adds authorization helpers for property fields and values * Make sure that users cannot lock themselves out of property fields * Migrate permissions from a JSON column to three normalized columns * Remove the audit comment * Use target level constants in authorization * Log authorization membership failures * Rename admin to sysadmin * Adds the Property System Architecture v2 API endpoints * Adds permission checks to the create field endpoint * Add target access checks to value endpoints * Add default branches for object_type and target_type and extra guards for cursor client4 methods * Fix vet API mismatch * Fix error checks * Fix linter * Add merge semantics for property patch logic and API endpoint * Fix i18n * Fix duplicated patch elements and early return on bad cursor * Update docs to use enums * Fix i18n sorting * Update app layer to return model.AppError * Adds a limit to the number of property values that can be patched in the same request * Adds websocket messages for the PSAv2 API events * Add IsPSAv2 helper to the property field for clarity * Add guard against nil returns on field deletion * Add docs to the websocket endpoints --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> * migrations: consolidate views migrations and reorder after master - Merged 000165 (create Views) with 000167 (drop Icon) since Icon was never needed - Renumbered branch migrations 159-166 → 160-167 so master's 000159 (deduplicate_policy_names) runs first - Regenerated migrations.list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add API endpoint to retrieve posts for a specific view (#35604) Automatic Merge * Apply fixes after merge * Return a more specific error from getting multiple fields * Prevent getting broadcast params on field deletion if not needed * Remove duplicated migration code * Update property conflict code to always use master * Adds nil guard when iterating on property fields * Check that permission level is valid before getting rejected by the database * Validate correctness on TargetID for PSAv2 fields * Avoid PSAv1 using permissions or protected * Fix test data after validation change * Fix flaky search test * Adds more posts for filter use cases to properly test exclusions --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es> Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com> Co-authored-by: Julien Tant <julien@craftyx.fr> Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Julien Tant <785518+JulienTant@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 05:36:35 -04:00
- name: type
in: query
description: Filter posts by type.
schema:
type: string
responses:
"200":
description: Post list retrieval successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostList"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/users/{user_id}/channels/{channel_id}/posts/unread":
get:
tags:
- posts
summary: Get posts around oldest unread
description: >
Get the oldest unread post in the channel for the given user as well as
the posts around it.
The returned list is sorted in descending order (most recent post first).
##### Permissions
Must be logged in as the user or have `edit_other_users` permission, and must have `read_channel` permission for the channel.
__Minimum server version__: 5.14
operationId: GetPostsAroundLastUnread
parameters:
- name: user_id
in: path
description: ID of the user
required: true
schema:
type: string
- name: channel_id
in: path
description: The channel ID to get the posts for
required: true
schema:
type: string
- name: limit_before
in: query
description: Number of posts before the oldest unread posts. Maximum is 200 posts
if limit is set greater than that.
schema:
type: integer
default: 60
maximum: 200
minimum: 0
- name: limit_after
in: query
description: Number of posts after and including the oldest unread post. Maximum is
200 posts if limit is set greater than that.
schema:
type: integer
default: 60
maximum: 200
minimum: 1
- name: skipFetchThreads
in: query
description: Whether to skip fetching threads or not
schema:
type: boolean
default: false
- name: collapsedThreads
in: query
description: Whether the client uses CRT or not
schema:
type: boolean
default: false
- name: collapsedThreadsExtended
in: query
description: Whether to return the associated users as part of the response or not
schema:
type: boolean
default: false
responses:
"200":
description: Post list retrieval successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostList"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/teams/{team_id}/posts/search":
post:
tags:
- posts
summary: Search for team posts
description: |
Search posts in the team and from the provided terms string.
##### Permissions
Must be authenticated and have the `view_team` permission.
operationId: SearchPosts
parameters:
- name: team_id
in: path
description: Team GUID
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- terms
- is_or_search
properties:
terms:
type: string
description: The search terms as inputed by the user. To search for posts
from a user include `from:someusername`, using a user's
username. To search in a specific channel include
`in:somechannel`, using the channel name (not the display
name).
is_or_search:
type: boolean
description: Set to true if an Or search should be performed vs an And
search.
time_zone_offset:
type: integer
default: 0
description: Offset from UTC of user timezone for date searches.
include_deleted_channels:
type: boolean
description: Set to true if deleted channels should be included in the
search. (archived channels)
page:
type: integer
default: 0
description: The page to select. (Only works with Elasticsearch)
per_page:
type: integer
default: 60
description: The number of posts per page. (Only works with Elasticsearch)
description: The search terms and logic to use in the search.
required: true
responses:
"200":
description: Post list retrieval successful
content:
application/json:
schema:
$ref: "#/components/schemas/PostListWithSearchMatches"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/pin":
post:
tags:
- posts
summary: Pin a post to the channel
description: >
Pin a post to a channel it is in based from the provided post id string.
##### Permissions
Must be authenticated and have the `read_channel` permission to the channel the post is in.
operationId: PinPost
parameters:
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
responses:
"200":
description: Pinned post successful
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/unpin":
post:
tags:
- posts
summary: Unpin a post to the channel
description: >
Unpin a post to a channel it is in based from the provided post id
string.
##### Permissions
Must be authenticated and have the `read_channel` permission to the channel the post is in.
operationId: UnpinPost
parameters:
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
responses:
"200":
description: Unpinned post successful
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/{post_id}/actions/{action_id}":
post:
tags:
- posts
summary: Perform a post action
description: >
Perform a post action, which allows users to interact with integrations
through posts.
##### Permissions
Must be authenticated and have the `read_channel` permission to the channel the post is in.
operationId: DoPostAction
parameters:
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
- name: action_id
in: path
description: Action GUID
required: true
schema:
type: string
responses:
"200":
description: Post action successful
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/posts/ids":
post:
tags:
- posts
summary: Get posts by a list of ids
description: >
Fetch a list of posts based on the provided postIDs
##### Permissions
Must have `read_channel` permission for the channel the post is in or if the channel is public, have the `read_public_channels` permission for the team.
operationId: getPostsByIds
requestBody:
content:
application/json:
schema:
type: array
items:
type: string
description: List of post ids
required: true
responses:
"200":
description: Post list retrieval successful
headers:
Has-Inaccessible-Posts:
schema:
type: boolean
description: Indicates whether the posts have been truncated as per the cloud's plan limit.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/users/{user_id}/posts/{post_id}/reminder":
post:
tags:
- posts
summary: Set a post reminder
description: >
Set a reminder for the user for the post.
##### Permissions
Must have `read_channel` permission for the channel the post is in.
__Minimum server version__: 7.2
operationId: SetPostReminder
parameters:
- name: user_id
in: path
description: User GUID
required: true
schema:
type: string
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- target_time
properties:
target_time:
type: integer
description: Target time for the reminder
description: Target time for the reminder
required: true
responses:
"200":
description: Reminder set successfully
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"/api/v4/users/{user_id}/posts/{post_id}/ack":
post:
tags:
- posts
summary: Acknowledge a post
description: >
Acknowledge a post that has a request for acknowledgements.
##### Permissions
Must have `read_channel` permission for the channel the post is in.<br/>
Must be logged in as the user or have `edit_other_users` permission.
__Minimum server version__: 7.7
operationId: SaveAcknowledgementForPost
parameters:
- name: user_id
in: path
description: User GUID
required: true
schema:
type: string
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
responses:
"200":
description: Acknowledgement saved successfully
content:
application/json:
schema:
$ref: "#/components/schemas/PostAcknowledgement"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
delete:
tags:
- posts
summary: Delete a post acknowledgement
description: >
Delete an acknowledgement form a post that you had previously acknowledged.
##### Permissions
Must have `read_channel` permission for the channel the post is in.<br/>
Must be logged in as the user or have `edit_other_users` permission.<br/>
The post must have been acknowledged in the previous 5 minutes.
__Minimum server version__: 7.7
operationId: DeleteAcknowledgementForPost
parameters:
- name: user_id
in: path
description: User GUID
required: true
schema:
type: string
- name: post_id
in: path
description: Post GUID
required: true
schema:
type: string
responses:
"200":
description: Acknowledgement deleted successfully
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
Feature: Wrangler (#23602) * Migrate feature/wrangler to mono-repo * Add wrangler files * Fix linters, types, etc * Fix snapshots * Fix playwright * Fix pipelines * Fix more pipeline * Fixes for pipelines * More changes for pipeline * Fix types * Add support for a feature flag, but leave it defaulted on for spinwick usage for now * Update snapshot * fix js error when removing last value of multiselect, support CSV marshaling to string array for textsetting * Fix linter * Remove TODO * Remove another TODO * fix tests * Fix i18n * Add server tests * Fix linter * Fix linter * Use proper icon for dot menu * Update snapshot * Add Cypress UI tests for various entrypoints to move thread modal, split SCSS out from forward post into its own thing * clean up * fix linter * More cleanup * Revert files to master * Fix linter for e2e tests * Make ForwardPostChannelSelect channel types configurable with a prop * Add missing return * Fixes from PR feedback * First batch of PR Feedback * Another batch of PR changes * Fix linter * Update snapshots * Wrangler system messages are translated to each user's locale * Initially translate Wrangler into system locale rather than initiating user * More fixes for PR Feedback * Fix some server tests * More updates with master. Fixes around pipelines. Enforce Enterprise license on front/back end * Add tests for dot_menu * More pipeline fixes * Fix e2etests prettier * Update cypress tests, change occurrences of 'Wrangler' with 'Move Thread' * Fix linter * Remove enterprise lock * A couple more occurrences of wrangler strings, and one more enterprise lock * Fix server tests * Fix i18n * Fix e2e linter * Feature flag shouldn't be on by default * Enable move threads feature in smoke tests (#25657) * enable move threads feature * add @prod tag * Fix move_thread_from_public_channel e2e test * Fix e2e style --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
2023-12-11 15:27:34 -05:00
"/api/v4/posts/{post_id}/move":
post:
tags:
- posts
summary: Move a post (and any posts within that post's thread)
description: >
Move a post/thread to another channel.
Feature: Wrangler (#23602) * Migrate feature/wrangler to mono-repo * Add wrangler files * Fix linters, types, etc * Fix snapshots * Fix playwright * Fix pipelines * Fix more pipeline * Fixes for pipelines * More changes for pipeline * Fix types * Add support for a feature flag, but leave it defaulted on for spinwick usage for now * Update snapshot * fix js error when removing last value of multiselect, support CSV marshaling to string array for textsetting * Fix linter * Remove TODO * Remove another TODO * fix tests * Fix i18n * Add server tests * Fix linter * Fix linter * Use proper icon for dot menu * Update snapshot * Add Cypress UI tests for various entrypoints to move thread modal, split SCSS out from forward post into its own thing * clean up * fix linter * More cleanup * Revert files to master * Fix linter for e2e tests * Make ForwardPostChannelSelect channel types configurable with a prop * Add missing return * Fixes from PR feedback * First batch of PR Feedback * Another batch of PR changes * Fix linter * Update snapshots * Wrangler system messages are translated to each user's locale * Initially translate Wrangler into system locale rather than initiating user * More fixes for PR Feedback * Fix some server tests * More updates with master. Fixes around pipelines. Enforce Enterprise license on front/back end * Add tests for dot_menu * More pipeline fixes * Fix e2etests prettier * Update cypress tests, change occurrences of 'Wrangler' with 'Move Thread' * Fix linter * Remove enterprise lock * A couple more occurrences of wrangler strings, and one more enterprise lock * Fix server tests * Fix i18n * Fix e2e linter * Feature flag shouldn't be on by default * Enable move threads feature in smoke tests (#25657) * enable move threads feature * add @prod tag * Fix move_thread_from_public_channel e2e test * Fix e2e style --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
2023-12-11 15:27:34 -05:00
THIS IS A BETA FEATURE. The API is subject to change without notice.
##### Permissions
Must have `read_channel` permission for the channel the post is in.
Must have `write_post` permission for the channel the post is being moved to.
__Minimum server version__: 9.3
operationId: MoveThread
parameters:
- name: post_id
in: path
description: The identifier of the post to move
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- channel_id
properties:
channel_id:
type: string
description: The channel identifier of where the post/thread is to be moved
description: The channel identifier of where the post/thread is to be moved
required: true
responses:
"200":
description: Post moved successfully
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"501":
$ref: "#/components/responses/NotImplemented"
Feature edit attachments (#29769) * Updated patch/update post API to allow file modification (#29447) * WIP * WIP * Atatched new files ton post * WIP: deleting removed files * Deleted removed files and invalidated file metadata cache * removed file ignore logif from update post API * Added TestFindExclusives * Added tests for DeleteForPostByIds * Added app layer tests * Added tests * Added API level tests * test enhancements * Fixed a test * Edit history include file metadata (#29505) * Send file metadata in edit history metadata * Added app tests * Added store tests * Added tests for populateEditHistoryFileMetadata{ * Added cache to avoid repetitigve DB calls for edits with only message changes * Added API tests * i18m fix * removed commented code * Improved test helper * Show attachments in edit history RHS (#29519) * Send file metadata in edit history metadata * Added app tests * Added store tests * Added tests for populateEditHistoryFileMetadata{ * Added cache to avoid repetitigve DB calls for edits with only message changes * Added API tests * i18m fix * WIUP: displa files in edit * removed commented code * Displayed file in edit history * Handled file icon * Fixed closing history component on clicking on file * Simplified selector * Simplified selector * Improved test helper * Disabled action menu on edit history file * Added tests * Improved selector * Updated snapshot * review Fixes * restructured componnets * Updated test * Updated test * Restore post api (#29643) * Restore post version API WIP * Undelete files WIP * Added store tests * Created post restore API * Updated updatepost safeUpdate signature * review fixex and improvements * Fixed an app test * Added API laer tests * Added API tests and OpenAPI specs * Fixed a typo * Allow editing files when editing posts (#29709) * WIP - basic view files when editing post * Cleanup * bg color * Added text editor tests for files * WIP * WIP * removed debug log * Allowed admin to add and remove files on someone else's post * Handled drafts and scheduled posts * linter fixes * Updated snapshot * server test fix * CI * Added doc * Restore post api integration (#29719) * WIP - basic view files when editing post * Cleanup * bg color * Added text editor tests for files * WIP * WIP * removed debug log * Allowed admin to add and remove files on someone else's post * Handled drafts and scheduled posts * linter fixes * Updated snapshot * server test fix * Used new API to restore post * handled edut limit and undo * lint fix * added comments * Fixed edit post item tests * Fixed buttons * Aded snapshots * fix test * Updated snapshot * Minor fixes * fixed snapshot * Edit file dnd area (#29763) * dnd wip * DND continued * Supported multiple unbind dragster funcs * lint fixes * Got center channel file drop working when editing a post * file dnd working with center channel and rhs * file dnd working with center channel and rhs * removed unneeded stopPropogation calls * cleanup * DND overlay fix * Lint fix * Advanced text editor test updates for file upload overlay * fixed use upload hook tests * Updated some more snapshots * minor cleanup * Updated i18n * removed need of array for dragster unbind events * lint fixes * edit history cursor * Fixed bugu causing faliure to delete empty posts (#29778) * Files in restore confirmation (#29781) * Added files to restore post confirmation dialog * Fixed post restore toast colors * Fixed restore bug * Fixed restore confirmation toast tests * a11y improvement and modal width fix * Edit attachment misc fixes (#29808) * Removed single image actions in restore post confirmation dialog * Fixed file drop overlay size and position * Made edit indiator accessible * Lint fix * Added bunch of more tests * ANother test migrated from enzyme to react testing library * More test enhancements * More test enhancements * More test enhancements * lint fixes * Fixed a test * Added missing snapshots * Test fixes
2025-01-13 07:46:56 -05:00
"/api/v4/posts/{post_id}/restore/{restore_version_id}":
post:
tags:
- posts
summary: Restores a past version of a post
description: >
Restores the post with `post_id` to its past version having the ID `restore_version_id`.
##### Permissions
Must have `read_channel` permission for the channel the post is in.
Must have `edit_post` permission for the channel the post is being moved to.
Must be the author of the post being restored.
__Minimum server version__: 10.5
operationId: RestorePostVersion
parameters:
- name: post_id
in: path
description: The identifier of the post to restore
required: true
schema:
type: string
- name: restore_version_id
in: path
description: The identifier of the past version of post to restore to
required: true
schema:
type: string
responses:
"200":
description: Post restored successful
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"501":
$ref: "#/components/responses/NotImplemented"
[MM-61758] Burn on read feature (#34703) * Add read receipt store for burn on read message types * update mocks * fix invalidation target * have consistent case on index creation * Add temporary posts table * add mock * add transaction support * reflect review comments * wip: Add reveal endpoint * user check error id instead * wip: Add ws events and cleanup for burn on read posts * add burn endpoint for explicitly burning messages * add translations * Added logic to associate files of BoR post with the post * Added test * fixes * disable pinning posts and review comments * MM-66594 - Burn on read UI integration (#34647) * MM-66244 - add BoR visual components to message editor * MM-66246 - BoR visual indicator for sender and receiver * MM-66607 - bor - add timer countdown and autodeletion * add the system console max time to live config * use the max expire at and create global scheduler to register bor messages * use seconds for BoR config values in BE * implement the read by text shown in the tooltip logic * unestack the posts from same receiver and BoR and fix styling * avoid opening reply RHS * remove unused dispatchers * persis the BoR label in the drafts * move expiration value to metadata * adjust unit tests to metadata insted of props * code clean up and some performance improvements; add period grace for deletion too * adjust migration serie number * hide bor messages when config is off * performance improvements on post component and code clean up * keep bor existing post functionality if config is disabled * Add read receipt store for burn on read message types * Add temporary posts table * add transaction support * reflect review comments * wip: Add reveal endpoint * user check error id instead * wip: Add ws events and cleanup for burn on read posts * avoid reacting to unrevealed bor messages * adjust migration number * Add read receipt store for burn on read message types * have consistent case on index creation * Add temporary posts table * add mock * add transaction support * reflect review comments * wip: Add reveal endpoint * user check error id instead * wip: Add ws events and cleanup for burn on read posts * add burn endpoint for explicitly burning messages * adjust post reveal and type with backend changes * use real config values, adjust icon usage and style * adjust the delete from from sender and receiver * improve self deleting logic by placing in badge, use burn endpoint * adjust websocket events handling for the read by sender label information * adjust styling for concealed and error state * update burn-on-read post event handling for improved recipient tracking and multi-device sync * replace burn_on_read with type in database migrations and model * remove burn_on_read metadata from PostMetadata and related structures * Added logic to associate files of BoR post with the post * Added test * adjust migration name and fix linter * Add read receipt store for burn on read message types * update mocks * have consistent case on index creation * Add temporary posts table * add mock * add transaction support * reflect review comments * wip: Add reveal endpoint * user check error id instead * wip: Add ws events and cleanup for burn on read posts * add burn endpoint for explicitly burning messages * Added logic to associate files of BoR post with the post * Added test * disable pinning posts and review comments * show attachment on bor reveal * remove unused translation * Enhance burn-on-read post handling and refine previous post ID retrieval logic * adjust the returning chunk to work with bor messages * read temp post from master db * read from master * show the copy link button to the sender * revert unnecessary check * restore correct json tag * remove unused error handling and clarify burn-on-read comment * improve type safety and use proper selectors * eliminate code duplication in deletion handler * optimize performance and add documentation * delete bor message for sender once all receivers reveal it * add burn on read to scheduled posts * add feature enable check * use master to avoid all read recipients race condition --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com> Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com> * squash migrations into single file * add configuration for the scheduler * don't run messagehasbeenposted hook * remove parallel tests on burn on read * add clean up for closing opened modals from previous tests * simplify delete menu item rendering * add cleanup step to close open modals after each test to prevent pollution * streamline delete button visibility logic for Burn on Read posts * improve reliability of closing post menu and modals by using body ESC key --------- Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com> Co-authored-by: Pablo Vélez <pablovv2012@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com>
2025-12-11 01:59:50 -05:00
"/api/v4/posts/{post_id}/reveal":
get:
tags:
- posts
summary: Reveal a burn-on-read post
description: >
Reveal a burn-on-read post. This endpoint allows a user to reveal a post
that was created with burn-on-read functionality. Once revealed, the post
content becomes visible to the user. If the post is already revealed and
not expired, this is a no-op. If the post has expired, an error will be returned.
##### Permissions
Must have `read_channel` permission for the channel the post is in.<br/>
Must be a member of the channel the post is in.<br/>
Cannot reveal your own post.
##### Feature Flag
Requires `BurnOnRead` feature flag and Enterprise Advanced license.
__Minimum server version__: 11.2
operationId: RevealPost
parameters:
- name: post_id
in: path
description: The identifier of the post to reveal
required: true
schema:
type: string
responses:
"200":
description: Post revealed successfully
headers:
Has-Inaccessible-Posts:
schema:
type: boolean
description: This header is included with the value "true" if the post is past the cloud's plan limit.
content:
application/json:
schema:
$ref: "#/components/schemas/Post"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"501":
$ref: "#/components/responses/NotImplemented"
"/api/v4/posts/{post_id}/burn":
delete:
tags:
- posts
summary: Burn a burn-on-read post
description: >
Burn a burn-on-read post. This endpoint allows a user to burn a post that
was created with burn-on-read functionality. If the user is the author of
the post, the post will be permanently deleted. If the user is not the author,
the post will be expired for that user by updating their read receipt expiration
time. If the user has not revealed the post yet, an error will be returned.
If the post is already expired for the user, this is a no-op.
##### Permissions
Must have `read_channel` permission for the channel the post is in.<br/>
Must be a member of the channel the post is in.
##### Feature Flag
Requires `BurnOnRead` feature flag and Enterprise Advanced license.
__Minimum server version__: 11.2
operationId: BurnPost
parameters:
- name: post_id
in: path
description: The identifier of the post to burn
required: true
schema:
type: string
responses:
"200":
description: Post burned successfully
headers:
Has-Inaccessible-Posts:
schema:
type: boolean
description: This header is included with the value "true" if the post is past the cloud's plan limit.
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOK"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"501":
$ref: "#/components/responses/NotImplemented"
"/api/v4/posts/rewrite":
post:
tags:
- posts
summary: Rewrite a message using AI
description: >
Rewrite a message using AI based on the specified action. The message will be
processed by an AI agent and returned in a rewritten form.
##### Permissions
Must be authenticated.
__Minimum server version__: 11.2
operationId: RewriteMessage
requestBody:
content:
application/json:
schema:
type: object
required:
- agent_id
- message
- action
properties:
agent_id:
type: string
description: The ID of the AI agent to use for rewriting
message:
type: string
description: The message text to rewrite
action:
type: string
description: The rewrite action to perform
enum:
- custom
- shorten
- elaborate
- improve_writing
- fix_spelling
- simplify
- summarize
custom_prompt:
type: string
description: Custom prompt for rewriting. Required when action is "custom", optional otherwise.
description: Rewrite request object
required: true
responses:
"200":
description: Message rewritten successfully
content:
application/json:
schema:
type: object
properties:
rewritten_text:
type: string
description: The rewritten message text
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"500":
description: Internal server error
content:
application/json:
schema:
$ref: "#/components/schemas/AppError"