Feature scheduled messages (#28932)
* Create scheduled post api (#27920) * Added migration files for Postgres * Added migrations for MySQL * Added store method * Added API and store tests * Renamed migration after syncing with master * Added app layer tests * API is ready * API is ready * API is ready * Renamed migration after syncing with master * Updated migration list * Fixed retry layer tests * Allowed posts with empty messages * Review fixes * Reverted an incorrect change * Renamed migration and fixed ID assignment * CI * Send post button changes (#28019) * added Split button * WIP * Added core menu options * WIP * WIP * WIP * Handled displaying error in creating scheduled post * lint fixes * webapp i18n fix * Review fixes * Fixed a webapp test * A few more fixes * Removed a duplicate comment * Scheduled post job (#28088) * Added the job function * Added query for fetching scheduled posts for pricessing * WIP * WIP * WIP * WIP * WIP * WIP * Reafactoring of scheduled post job * Lint fixes * Updated i18n files * FInishing touches * Added tests for GetScheduledPosts * Added tests for PermanentlyDeleteScheduledPosts * Updated all layer * Some changes as discussed with team * Added tests for UpdatedScheduledPost * Code review refactoring * Added job test * MM-60120 - Custom time selection (#28120) * Added a common date time picker modal and used it for post reminder * Added a common date time picker modal and used it for post reminderggp * Added modal for custom schedule time and fixed TZ issue * WIP * Removed event from useSubmit hook * Removed event from useSubmit hook * Added timezone handling * fixed type error * Updated i18n strings * Minor cleanup * updated snapshots * review fixes * Handled event * Supported for having a DM thread open in RHS while in a regular channel * Review fixes * MM-60136 - Scheduled messages tab (#28133) * WIP * WIP * Created Tabs and Tab wrapper with added styling * Added API to get scheduled posts * WIP * Displated scheduled post count * i18n fix * Added tests * Handled asetting active tab absed on URL: * Reverted unintended change * Added API to client ad OpenAPI specs * Renamed file * Adding fileinfo to schedule posts * Partial review fixes * Made get scheduled post API return posts by teamID * review fixes * Moved scheduled post redux code to MM-redux package * Usedd selector factory * WIP: * WIP: * Lint fix * Fixed an incorrect openapi spec file * Removed redundent permission check * Clreaed scheduled post data on logout * Removed unused i18n string: * lint fix * Render scheduled posts (#28208) * WIP * WIP * Created Tabs and Tab wrapper with added styling * Added API to get scheduled posts * WIP * Displated scheduled post count * i18n fix * Added tests * Handled asetting active tab absed on URL: * Reverted unintended change * Added API to client ad OpenAPI specs * Renamed file * Created common component for draft list item * WIP * WIP * Adding fileinfo to schedule posts * Basic rendering * Added count badge to tabs * WIP * Made the Drafts LHS iteam appear if no drafts exist but scheduled posts do * Fixed icon size * Partial review fixes * Made get scheduled post API return posts by teamID * Handled initial vs team switch load * Displayed scheduled date in panel header * Added error message and error indiocator * WIP * review fixes * WIP Adding error reason tag * Added error codes * Moved scheduled post redux code to MM-redux package * Usedd selector factory * WIP: * WIP: * Lint fix * Fixed an incorrect openapi spec file * Removed redundent permission check * Clreaed scheduled post data on logout * Removed unused i18n string: * lint fix * Opened rescheduling modal * Updated graphic for empty state of schduled post list * Added delete scheduled post option and modal * Badge and timezone fix * WIP: * Added send now confirmation modal * lint * Webapp i18n fix * Fixed webapp test * Fixed a bug where DM/GM scheduled posts weren't immideatly showing up in UI * Minor fixes * WIP * Review fixes * Review fixes * Optimisations * Fixed reducer name * Moment optimizatin * Updated route check * MM-60144 - added API to update a scheduled post (#28248) * WIP * Added api and ap layer for update scheduled post ̛̦̄ * Added API to OpenAI specs, Go client and TS client * removed permissio check * Added tests * Fixed tests * Added PreUpdate method on scheduled post model * MM-60131 - Reschedule post integration (#28281) * Handled rescheduling post in webapp * Added error handling * MM-60146 - Delete scheduled post api (#28265) * WIP * Added api and ap layer for update scheduled post ̛̦̄ * Added API to OpenAI specs, Go client and TS client * removed permissio check * Added tests * Fixed tests * Added PreUpdate method on scheduled post model * Added delete scheduled post API * Added API to Go client and OpenAPI specs * Added API to TS client * Added tests * CI * Rmeoved two incorrect code comments * MM-60653 - Integrated delete scheduled post API (#28296) * Integrated delete scheduled apost API * Lint fix * Review fixes * Excluded draft checks from scheduled posts (#28370) * Excluded draft checks from scheduled posts * Added a removed todo * MM-60125 - Scheduled post channel indicator (#28320) * Integrated delete scheduled apost API * Lint fix * Added state for storing scheduled posts by channel ID * Refactored redux store to store scheudled posts by ID, thens tore IDs everywhere * Refactored redux store to store scheudled posts by ID, thens tore IDs everywhere * WIP * Added scheduled post indiocator * Handled single and multiple scheudled posts * Review fixes * Fixed styling and handled center channel, RHS and threads view * Lint fix * i18n fix * Fixed a cycling dependency * Lint fix * Added some more comments * Updated styling * Review fixes * Added common component for remote user time and scheduled post indicator * Updated scheduled post count * Minor change * Moved CSS code around * Fixed a bug where files in scheduled post didn't show up until refresh (#28359) --------- Co-authored-by: Daniel Espino García <larkox@gmail.com> * Scheduled post config (#28485) * Added config * Added config on server and webapp side * Added config check in server and webapp * Added license check * Added license check * Added placeholder help text * Added license check to job * Fixed job test * Review fixes * Updated English text * Review fixes * MM-60118 - Added index on ScheduledPosts table (#28579) * Added index * Updated indexes * Scheduled posts misc fixes (#28625) * Added detailed logging for scheduled post job * Limited scheduled posts processing to 24 hours * Marked old scheduled posts as unable to send * Added t5ests * converted some logs to trace level * Fixed a bug causing error message to show up on deleting a scheduled post in a deleted thread (#28630) * Fixed scheduled posts link in RHS (#28659) * Fixed scheduled posts link in RHS * Review fixes * Fix permission name in scheduled posts by team (#28580) * Fix permission name * fix wording --------- Co-authored-by: Mattermost Build <build@mattermost.com> * FIxed width of generic modal header to fix browser channel modal (#28639) * Only consider error-free scheduled posts for indicator in channel and RHS (#28683) * Show only errro free scheudled posts in post box indicator * Fixed a bug to handle no scheduled posts * Fixed draft and scheudled post UI in mobile view (#28680) * MM-60873 and MM-60872 - Fixed a bug with updating scheduled posts (#28656) * Fixed a bug with updating scheduled posts * Better selectors * MOved shceuled post message length validation to app layer * MM-60732 - Scheduled posts channel link now takes you to the first scheduled post in channel/thread in list (#28768) * Ordered scheudle dposts by schgeudled at nad create at * Ordered in client * Added scroll to target * Removed classname prop * Fixed tests * Added doc * Import fix * MM-60961 - Fixed a bug where API used incoming create at date for scheduled post (#28703) * Fixed a bug where API used incoming create at date for scheduled post * Stopped sending created at value for scheduled post * MM-60785 - Fixed a bug where scheduled posts of channel we are no longer member of didn't show up (#28637) * Fixed a bug where scheduled posts of channel we are no longer member of didn't show up * Added a comment * CI * Used data loader to optimise laoding missing channels * Minor refactoring * MM-60963 - Added common checks for post and scheduled posts (#28713) * Added commen checks for post and scheuled posts * Sanitised scheduled posts * Fixed tests * Splitted post checks into app and context functions * Added checks on scheduiled posts job as well: * i18n fix * Fixed a test * Renamed a func * removed duplicate check * Scheduled posts UI fixes (#28828) * Fixed send button and time picker borders * Fixed center alignment of time picker * Removed on for today and tomorrow * Lint fix * Date time modal hover state fix * Badge fix * Fixed a mnerge issue * Scheduled Post send now and add schedule on draft (#28851) * Added send now option on scheduled posts * Minor refactoring * WIP * WIP * WIP * Lint fix * i18n fix * Snapshot update * Review fixes * Scheduled post inline editing (#28893) * Added send now option on scheduled posts * Minor refactoring * WIP * WIP * WIP * Lint fix * i18n fix * Snapshot update * Displayed editing component in scheduled post * Added handling for updating scheduled post * Handle events * Fixed escape key issue in scheudled post editing * Fixes * Displayed error message for editing error * Don't show mention warning * Handled dev mode (#28918) * MInor fixes * client fix * Fixes * CI * Removed dev mode behaviour temperorily (#29008) --------- Co-authored-by: Daniel Espino García <larkox@gmail.com> Co-authored-by: Eva Sarafianou <eva.sarafianou@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
aaf9234c8e
Коммит
e281b3f37e
357
server/channels/app/scheduled_post_job.go
Обычный файл
357
server/channels/app/scheduled_post_job.go
Обычный файл
@@ -0,0 +1,357 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
getPendingScheduledPostsPageSize = 100
|
||||
scheduledPostBatchWaitTime = 1 * time.Second
|
||||
)
|
||||
|
||||
func (a *App) ProcessScheduledPosts(rctx request.CTX) {
|
||||
rctx = rctx.WithLogger(rctx.Logger().With(mlog.String("component", "scheduled_post_job")))
|
||||
rctx.Logger().Debug("ProcessScheduledPosts called...")
|
||||
|
||||
if !*a.Config().ServiceSettings.ScheduledPosts {
|
||||
rctx.Logger().Debug("ProcessScheduledPosts exiting as the feature is turned off via ServiceSettings.ScheduledPosts setting...")
|
||||
return
|
||||
}
|
||||
|
||||
if a.License() == nil {
|
||||
rctx.Logger().Debug("ProcessScheduledPosts exiting as no license is available")
|
||||
return
|
||||
}
|
||||
|
||||
beforeTime := model.GetMillis()
|
||||
afterTime := beforeTime - (24 * 60 * 60 * 1000) // subtracting 24 hours from beforeTime
|
||||
lastScheduledPostId := ""
|
||||
|
||||
for {
|
||||
// we wait some time before processing each batch to avoid hammering the database with too many requests.
|
||||
time.Sleep(scheduledPostBatchWaitTime)
|
||||
rctx.Logger().Debug("ProcessScheduledPosts: fetching page of pending scheduled posts...")
|
||||
|
||||
scheduledPostsBatch, err := a.Srv().Store().ScheduledPost().GetPendingScheduledPosts(beforeTime, afterTime, lastScheduledPostId, getPendingScheduledPostsPageSize)
|
||||
if err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.ProcessScheduledPosts: failed to fetch pending scheduled posts page from database",
|
||||
mlog.Int("before_time", beforeTime),
|
||||
mlog.String("last_scheduled_post_id", lastScheduledPostId),
|
||||
mlog.Int("items_per_page", getPendingScheduledPostsPageSize),
|
||||
mlog.Err(err),
|
||||
)
|
||||
|
||||
// Break the loop if we can't fetch the page.
|
||||
// Missed posts will be processed in job's next round.
|
||||
// Since we don't know any item's details, we can't fetch the next page as well.
|
||||
// We could retry here but that's the same as trying in job's next round.
|
||||
break
|
||||
}
|
||||
|
||||
rctx.Logger().Debug("ProcessScheduledPosts: entries found in page of pending scheduled posts", mlog.Int("entries", len(scheduledPostsBatch)))
|
||||
if len(scheduledPostsBatch) == 0 {
|
||||
rctx.Logger().Debug("ProcessScheduledPosts: skipping as there are no pending scheduled")
|
||||
// break loop if there are no more scheduled posts
|
||||
break
|
||||
}
|
||||
|
||||
// Saving the last item to use as marker for next page
|
||||
lastScheduledPostId = scheduledPostsBatch[len(scheduledPostsBatch)-1].Id
|
||||
beforeTime = scheduledPostsBatch[len(scheduledPostsBatch)-1].ScheduledAt
|
||||
|
||||
if err := a.processScheduledPostBatch(rctx, scheduledPostsBatch); err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.ProcessScheduledPosts: failed to process scheduled posts batch",
|
||||
mlog.Int("before_time", beforeTime),
|
||||
mlog.String("last_scheduled_post_id", lastScheduledPostId),
|
||||
mlog.Int("items_per_page", getPendingScheduledPostsPageSize),
|
||||
mlog.Err(err),
|
||||
)
|
||||
|
||||
// failure to process one batch doesn't mean other batches will fail as well.
|
||||
// Continue processing next batch. The posts that failed in this batch will be picked
|
||||
// up when the job next runs.
|
||||
continue
|
||||
}
|
||||
|
||||
rctx.Logger().Debug("ProcessScheduledPosts: finished processing a page of pending scheduled posts.")
|
||||
|
||||
if len(scheduledPostsBatch) < getPendingScheduledPostsPageSize {
|
||||
// if we got less than page size worth of scheduled posts, it indicates
|
||||
// that we have no more pending scheduled posts. So, we can break instead of making
|
||||
// an additional database call as we know there are going to be no records in there.
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// once all scheduled posts are processed, we need to update and close the old ones
|
||||
// as we don't process pending scheduled posts more than 24 hours old.
|
||||
if err := a.Srv().Store().ScheduledPost().UpdateOldScheduledPosts(beforeTime); err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.ProcessScheduledPosts: failed to update old scheduled posts",
|
||||
mlog.Int("before_time", beforeTime),
|
||||
mlog.Err(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// processScheduledPostBatch processes one batch
|
||||
func (a *App) processScheduledPostBatch(rctx request.CTX, scheduledPosts []*model.ScheduledPost) error {
|
||||
rctx.Logger().Debug("processScheduledPostBatch called...")
|
||||
var failedScheduledPosts []*model.ScheduledPost
|
||||
var successfulScheduledPostIDs []string
|
||||
|
||||
for i := range scheduledPosts {
|
||||
rctx.Logger().Trace("processScheduledPostBatch processing scheduled post", mlog.String("scheduled_post_id", scheduledPosts[i].Id))
|
||||
scheduledPost, err := a.postScheduledPost(rctx, scheduledPosts[i])
|
||||
if err != nil {
|
||||
rctx.Logger().Debug("processScheduledPostBatch scheduled post processing failed", mlog.String("scheduled_post_id", scheduledPosts[i].Id), mlog.Err(err))
|
||||
failedScheduledPosts = append(failedScheduledPosts, scheduledPost)
|
||||
continue
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("processScheduledPostBatch scheduled post processing successful", mlog.String("scheduled_post_id", scheduledPosts[i].Id))
|
||||
successfulScheduledPostIDs = append(successfulScheduledPostIDs, scheduledPost.Id)
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("processScheduledPostBatch handling successful scheduled posts...", mlog.Int("count", len(successfulScheduledPostIDs)))
|
||||
if err := a.handleSuccessfulScheduledPosts(rctx, successfulScheduledPostIDs); err != nil {
|
||||
return errors.Wrap(err, "App.processScheduledPostBatch: failed to handle successfully posted scheduled posts")
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("processScheduledPostBatch handling failed scheduled posts...", mlog.Int("count", len(failedScheduledPosts)))
|
||||
a.handleFailedScheduledPosts(rctx, failedScheduledPosts)
|
||||
rctx.Logger().Debug("processScheduledPostBatch finished...")
|
||||
return nil
|
||||
}
|
||||
|
||||
// postScheduledPost processes an individual scheduled post
|
||||
func (a *App) postScheduledPost(rctx request.CTX, scheduledPost *model.ScheduledPost) (*model.ScheduledPost, error) {
|
||||
rctx.Logger().Debug("postScheduledPost called...", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
|
||||
// we'll process scheduled posts one by one.
|
||||
// If an error occurs, we'll log it and move onto the next scheduled post
|
||||
|
||||
rctx.Logger().Trace("postScheduledPost fetching channel for scheduled post", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("channel_id", scheduledPost.ChannelId))
|
||||
channel, appErr := a.GetChannel(rctx, scheduledPost.ChannelId)
|
||||
if appErr != nil {
|
||||
if appErr.StatusCode == http.StatusNotFound {
|
||||
rctx.Logger().Debug("postScheduledPost channel for scheduled post not found, setting error code", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("channel_id", scheduledPost.ChannelId), mlog.String("error_code", model.ScheduledPostErrorCodeChannelNotFound))
|
||||
|
||||
scheduledPost.ErrorCode = model.ScheduledPostErrorCodeChannelNotFound
|
||||
return scheduledPost, nil
|
||||
}
|
||||
|
||||
rctx.Logger().Error(
|
||||
"App.processScheduledPostBatch: failed to get channel for scheduled post",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorUnknownError),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
|
||||
scheduledPost.ErrorCode = model.ScheduledPostErrorUnknownError
|
||||
return scheduledPost, appErr
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("postScheduledPost checking if scheduled post can be posted", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
errorCode, err := a.canPostScheduledPost(rctx, scheduledPost, channel)
|
||||
scheduledPost.ErrorCode = errorCode
|
||||
if err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.processScheduledPostBatch: failed to check if scheduled post can be posted",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.Err(err),
|
||||
)
|
||||
|
||||
return scheduledPost, err
|
||||
}
|
||||
|
||||
if scheduledPost.ErrorCode != "" {
|
||||
rctx.Logger().Warn(
|
||||
"App.processScheduledPostBatch: skipping posting a scheduled post as `can post` check failed",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", scheduledPost.ErrorCode),
|
||||
)
|
||||
|
||||
return scheduledPost, fmt.Errorf("App.processScheduledPostBatch: skipping posting a scheduled post as `can post` check failed, error_code: %s", scheduledPost.ErrorCode)
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("postScheduledPost converting scheduled post to post", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
post, err := scheduledPost.ToPost()
|
||||
if err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.processScheduledPostBatch: failed to convert scheduled post to a post",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("error_code", model.ScheduledPostErrorUnknownError),
|
||||
mlog.Err(err),
|
||||
)
|
||||
|
||||
scheduledPost.ErrorCode = model.ScheduledPostErrorUnknownError
|
||||
return scheduledPost, err
|
||||
}
|
||||
|
||||
rctx.Logger().Trace("postScheduledPost posting the scheduled post", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
createPostFlags := model.CreatePostFlags{
|
||||
TriggerWebhooks: true,
|
||||
SetOnline: false,
|
||||
}
|
||||
_, appErr = a.CreatePost(rctx, post, channel, createPostFlags)
|
||||
if appErr != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.processScheduledPostBatch: failed to post scheduled post",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorUnknownError),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
|
||||
scheduledPost.ErrorCode = model.ScheduledPostErrorUnknownError
|
||||
return scheduledPost, appErr
|
||||
}
|
||||
|
||||
return scheduledPost, nil
|
||||
}
|
||||
|
||||
// canPostScheduledPost checks whether the scheduled post be created based on permissions and other checks.
|
||||
func (a *App) canPostScheduledPost(rctx request.CTX, scheduledPost *model.ScheduledPost, channel *model.Channel) (string, error) {
|
||||
rctx.Logger().Trace("canPostScheduledPost called...", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
|
||||
user, appErr := a.GetUser(scheduledPost.UserId)
|
||||
if appErr != nil {
|
||||
if appErr.Id == MissingAccountError {
|
||||
rctx.Logger().Debug("canPostScheduledPost user not found for scheduled post", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("user_id", scheduledPost.UserId), mlog.String("error_code", model.ScheduledPostErrorCodeUserDoesNotExist))
|
||||
return model.ScheduledPostErrorCodeUserDoesNotExist, nil
|
||||
}
|
||||
|
||||
rctx.Logger().Error(
|
||||
"App.canPostScheduledPost: failed to get user from database",
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorUnknownError),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
return model.ScheduledPostErrorUnknownError, errors.Wrapf(appErr, "App.canPostScheduledPost: failed to get user from database, userId: %s", scheduledPost.UserId)
|
||||
}
|
||||
|
||||
if user.DeleteAt != 0 {
|
||||
rctx.Logger().Debug("canPostScheduledPost user for scheduled posts is deleted", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("user_id", scheduledPost.UserId), mlog.String("error_code", model.ScheduledPostErrorCodeUserDeleted))
|
||||
return model.ScheduledPostErrorCodeUserDeleted, nil
|
||||
}
|
||||
|
||||
if channel.DeleteAt != 0 {
|
||||
rctx.Logger().Debug("canPostScheduledPost channel for scheduled post is archived", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("channel_id", channel.Id), mlog.String("error_code", model.ScheduledPostErrorCodeChannelArchived))
|
||||
return model.ScheduledPostErrorCodeChannelArchived, nil
|
||||
}
|
||||
|
||||
if scheduledPost.RootId != "" {
|
||||
rootPosts, _, appErr := a.GetPostsByIds([]string{scheduledPost.RootId})
|
||||
if appErr != nil {
|
||||
if appErr.StatusCode == http.StatusNotFound {
|
||||
rctx.Logger().Debug("canPostScheduledPost thread root post for scheduled post is missing", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("root_post_id", scheduledPost.RootId), mlog.String("error_code", model.ScheduledPostErrorThreadDeleted))
|
||||
return model.ScheduledPostErrorThreadDeleted, nil
|
||||
}
|
||||
|
||||
rctx.Logger().Error(
|
||||
"App.canPostScheduledPost: failed to get root post",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("root_post_id", scheduledPost.RootId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorUnknownError),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
|
||||
return model.ScheduledPostErrorUnknownError, errors.Wrapf(appErr, "App.canPostScheduledPost: failed to get root post, scheduled_post_id: %s, root_post_id: %s", scheduledPost.Id, scheduledPost.RootId)
|
||||
}
|
||||
|
||||
// you do get deleted posts from `GetPostsByIds`, so need to validate that as well
|
||||
if len(rootPosts) == 1 && rootPosts[0].Id == scheduledPost.RootId && rootPosts[0].DeleteAt != 0 {
|
||||
rctx.Logger().Debug("canPostScheduledPost thread root post is deleted", mlog.String("scheduled_post_id", scheduledPost.Id), mlog.String("root_post_id", scheduledPost.RootId), mlog.String("error_code", model.ScheduledPostErrorThreadDeleted))
|
||||
return model.ScheduledPostErrorThreadDeleted, nil
|
||||
}
|
||||
}
|
||||
|
||||
if appErr := userCreatePostPermissionCheckWithApp(rctx, a, scheduledPost.UserId, scheduledPost.ChannelId); appErr != nil {
|
||||
rctx.Logger().Debug(
|
||||
"canPostScheduledPost user does not have permission to create post in channel",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorCodeNoChannelPermission),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
return model.ScheduledPostErrorCodeNoChannelPermission, nil
|
||||
}
|
||||
|
||||
if appErr := PostHardenedModeCheckWithApp(a, false, scheduledPost.GetProps()); appErr != nil {
|
||||
rctx.Logger().Debug(
|
||||
"canPostScheduledPost hardened mode enabled: post contains props prohibited in hardened mode",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorInvalidPost),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
return model.ScheduledPostErrorInvalidPost, nil
|
||||
}
|
||||
|
||||
if appErr := PostPriorityCheckWithApp("ScheduledPostJob.postChecks", a, scheduledPost.UserId, scheduledPost.GetPriority(), scheduledPost.RootId); appErr != nil {
|
||||
rctx.Logger().Debug(
|
||||
"canPostScheduledPost post priority check failed",
|
||||
mlog.String("scheduled_post_id", scheduledPost.Id),
|
||||
mlog.String("user_id", scheduledPost.UserId),
|
||||
mlog.String("channel_id", scheduledPost.ChannelId),
|
||||
mlog.String("error_code", model.ScheduledPostErrorInvalidPost),
|
||||
mlog.Err(appErr),
|
||||
)
|
||||
return model.ScheduledPostErrorInvalidPost, nil
|
||||
}
|
||||
|
||||
rctx.Logger().Debug("canPostScheduledPost scheduled post can be posted", mlog.String("scheduled_post_id", scheduledPost.Id))
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (a *App) handleSuccessfulScheduledPosts(rctx request.CTX, successfulScheduledPostIDs []string) error {
|
||||
if len(successfulScheduledPostIDs) > 0 {
|
||||
// Successfully posted scheduled posts can be safely permanently deleted as no data is lost.
|
||||
// The data is moved into the posts table.
|
||||
err := a.Srv().Store().ScheduledPost().PermanentlyDeleteScheduledPosts(successfulScheduledPostIDs)
|
||||
if err != nil {
|
||||
rctx.Logger().Error(
|
||||
"App.handleSuccessfulScheduledPosts: failed to delete successfully posted scheduled posts",
|
||||
mlog.Int("successfully_posted_count", len(successfulScheduledPostIDs)),
|
||||
mlog.Err(err),
|
||||
)
|
||||
return errors.Wrap(err, "App.handleSuccessfulScheduledPosts: failed to delete successfully posted scheduled posts")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) handleFailedScheduledPosts(rctx request.CTX, failedScheduledPosts []*model.ScheduledPost) {
|
||||
for _, failedScheduledPost := range failedScheduledPosts {
|
||||
err := a.Srv().Store().ScheduledPost().UpdatedScheduledPost(failedScheduledPost)
|
||||
if err != nil {
|
||||
// we intentionally don't stop on error as its possible to continue updating other scheduled posts
|
||||
rctx.Logger().Error(
|
||||
"App.processScheduledPostBatch: failed to updated failed scheduled posts",
|
||||
mlog.String("scheduled_post_id", failedScheduledPost.Id),
|
||||
mlog.Err(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user