[CLD-7421][CLD-7420] Deprecate Self Serve: First Pass (#26668)
* Deprecate Self Serve: First Pass * Fix ci * Fix more ci * Remmove outdated server tests * Fix a missed spot opening purchase modal in Self Hosted * Fix i18n * Clean up some more server code, fix webapp test * Fix alignment of button * Fix linter * Fix i18n server side * Add back translation * Remove client functions * Put back client functions --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -239,44 +239,6 @@ func (es *Service) SendWelcomeEmail(userID string, email string, verified bool,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendCloudUpgradeConfirmationEmail(userEmail, name, date, locale, siteURL, workspaceName string, isYearly bool, embeddedFiles map[string]io.Reader) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
subject := T("api.templates.cloud_upgrade_confirmation.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["Title"] = T("api.templates.cloud_upgrade_confirmation.title")
|
||||
data.Props["SubTitle"] = T("api.templates.cloud_upgrade_confirmation_monthly.subtitle", map[string]any{"WorkspaceName": workspaceName, "Date": date})
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["ButtonURL"] = siteURL
|
||||
data.Props["Button"] = T("api.templates.cloud_welcome_email.button")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
|
||||
if isYearly {
|
||||
data.Props["SubTitle"] = T("api.templates.cloud_upgrade_confirmation_yearly.subtitle", map[string]any{"WorkspaceName": workspaceName})
|
||||
data.Props["ButtonURL"] = siteURL + "/admin_console/billing/billing_history"
|
||||
data.Props["Button"] = T("api.templates.cloud_welcome_email.yearly_plan_button")
|
||||
}
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_upgrade_confirmation", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isYearly {
|
||||
if err := es.SendMailWithEmbeddedFilesAndCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail, embeddedFiles, "CloudUpgradeConfirmationEmail"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := es.sendEmailWithCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail, "CloudUpgradeConfirmationEmail"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendCloudWelcomeEmail sends the cloud version of the welcome email
|
||||
func (es *Service) SendCloudWelcomeEmail(userEmail, locale, teamInviteID, workSpaceName, dns, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
@@ -972,378 +934,6 @@ func (es *Service) SendLicenseUpForRenewalEmail(email, name, locale, siteURL, ct
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendPaymentFailedEmail(email string, locale string, failedPayment *model.FailedPayment, planName, siteURL string) (bool, error) {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.payment_failed.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.payment_failed.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.payment_failed.info1", map[string]any{"CardBrand": failedPayment.CardBrand, "LastFour": failedPayment.LastFour})
|
||||
data.Props["SubTitle2"] = T("api.templates.payment_failed.info2")
|
||||
data.Props["FailedReason"] = failedPayment.FailureMessage
|
||||
data.Props["SubTitle3"] = T("api.templates.payment_failed.info3", map[string]any{"Plan": planName})
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_45.button")
|
||||
data.Props["IncludeSecondaryActionButton"] = false
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("payment_failed_body", data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "PaymentFailed"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (es *Service) SendNoCardPaymentFailedEmail(email string, locale string, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.payment_failed_no_card.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.payment_failed_no_card.title")
|
||||
data.Props["Info1"] = T("api.templates.payment_failed_no_card.info1")
|
||||
data.Props["Info3"] = T("api.templates.payment_failed_no_card.info3")
|
||||
data.Props["Button"] = T("api.templates.payment_failed_no_card.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("payment_failed_no_card_body", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "NoCardPaymentFailed"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendDelinquencyEmail7(email, locale, siteURL, planName string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.payment_failed.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_7.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_7.subtitle1")
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_7.subtitle2", map[string]any{"Plan": planName})
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_7.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_7_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency7"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (es *Service) SendDelinquencyEmail14(email, locale, siteURL, planName string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_14.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_14.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_14.subtitle1")
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_14.subtitle2")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_14.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_14_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency14"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (es *Service) SendDelinquencyEmail30(email, locale, siteURL, planName string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_30.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_30.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_30.subtitle1", map[string]any{"Plan": planName})
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_30.subtitle2")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_30.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["BulletListItems"] = []string{T("api.templates.delinquency_30.bullet.message_history"), T("api.templates.delinquency_30.bullet.files")}
|
||||
data.Props["LimitsDocs"] = T("api.templates.delinquency_30.limits_documentation")
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_30_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency30"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendDelinquencyEmail45(email, locale, siteURL, planName, delinquencyDate string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_45.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_45.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_45.subtitle1", map[string]any{"DelinquencyDate": delinquencyDate})
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_45.subtitle2")
|
||||
data.Props["SubTitle3"] = T("api.templates.delinquency_45.subtitle3")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_45.button")
|
||||
data.Props["IncludeSecondaryActionButton"] = false
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency45"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendDelinquencyEmail60(email, locale, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_60.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_60.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_60.subtitle1")
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_60.subtitle2")
|
||||
data.Props["SubTitle3"] = T("api.templates.delinquency_60.subtitle3")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_60.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["IncludeSecondaryActionButton"] = true
|
||||
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_60.downgrade_to_free")
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
// 45 day template is the same as the 60 day one so its reused
|
||||
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency60"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendDelinquencyEmail75(email, locale, siteURL, planName, delinquencyDate string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_75.subject", map[string]any{"Plan": planName})
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_75.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_75.subtitle1", map[string]any{"DelinquencyDate": delinquencyDate})
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_75.subtitle2", map[string]any{"Plan": planName})
|
||||
data.Props["SubTitle3"] = T("api.templates.delinquency_75.subtitle3")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_75.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["IncludeSecondaryActionButton"] = true
|
||||
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_75.downgrade_to_free")
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
// 45 day template is the same as the 75 day one so its reused
|
||||
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency75"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendDelinquencyEmail90(email, locale, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.delinquency_90.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.delinquency_90.title")
|
||||
data.Props["SubTitle1"] = T("api.templates.delinquency_90.subtitle1", map[string]any{"SiteURL": siteURL})
|
||||
data.Props["SubTitle2"] = T("api.templates.delinquency_90.subtitle2")
|
||||
data.Props["SubTitle3"] = T("api.templates.delinquency_90.subtitle3")
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["Button"] = T("api.templates.delinquency_90.button")
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["IncludeSecondaryActionButton"] = true
|
||||
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_90.secondary_action_button")
|
||||
data.Props["Footer"] = T("api.templates.copyright")
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_90_day_arrears", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail, "Delinquency90"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendCloudRenewalEmail60(email, locale, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.cloud_renewal_60.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.cloud_renewal_60.title")
|
||||
data.Props["SubTitle"] = T("api.templates.cloud_renewal.subtitle")
|
||||
// TODO: use the open delinquency modal action
|
||||
data.Props["ButtonURL"] = siteURL + "/admin_console/billing/subscription"
|
||||
data.Props["Button"] = T("api.templates.cloud_renewal.button")
|
||||
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["Image"] = "payment_processing.png"
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_renewal_notification", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendMail(email, subject, body, "CloudRenewal60"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendCloudRenewalEmail30(email, locale, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.cloud_renewal_30.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.cloud_renewal_30.title")
|
||||
data.Props["SubTitle"] = T("api.templates.cloud_renewal.subtitle")
|
||||
// TODO: use the open delinquency modal action
|
||||
data.Props["ButtonURL"] = siteURL + "/admin_console/billing/subscription"
|
||||
data.Props["Button"] = T("api.templates.cloud_renewal.button")
|
||||
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["Image"] = "payment_processing.png"
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_renewal_notification", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendMail(email, subject, body, "CloudRenewal30"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *Service) SendCloudRenewalEmail7(email, locale, siteURL string) error {
|
||||
T := i18n.GetUserTranslations(locale)
|
||||
|
||||
subject := T("api.templates.cloud_renewal_7.subject")
|
||||
|
||||
data := es.NewEmailTemplateData(locale)
|
||||
data.Props["SiteURL"] = siteURL
|
||||
data.Props["Title"] = T("api.templates.cloud_renewal_7.title")
|
||||
data.Props["SubTitle"] = T("api.templates.cloud_renewal.subtitle")
|
||||
// TODO: use the open delinquency modal action
|
||||
data.Props["ButtonURL"] = siteURL + "/admin_console/billing/subscription"
|
||||
data.Props["Button"] = T("api.templates.cloud_renewal.button")
|
||||
|
||||
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
|
||||
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
|
||||
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
|
||||
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
|
||||
data.Props["Image"] = "purchase_alert.png"
|
||||
|
||||
body, err := es.templatesContainer.RenderToString("cloud_renewal_notification", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := es.sendMail(email, subject, body, "CloudRenewal7"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
|
||||
// to renew the user license
|
||||
func (es *Service) SendRemoveExpiredLicenseEmail(ctaText, ctaLink, email, locale, siteURL string) error {
|
||||
|
||||
Ссылка в новой задаче
Block a user