Merge branch 'master' of github.com:mattermost/mattermost-server into MM-47853-true-up-review-telemetry-off-non-air-gapped
Этот коммит содержится в:
@@ -40,6 +40,7 @@ func (api *API) InitCloud() {
|
||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(getSubscription)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices", api.APISessionRequired(getInvoicesForSubscription)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/invoices/{invoice_id:[A-Za-z0-9]+}/pdf", api.APISessionRequired(getSubscriptionInvoicePDF)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription/expand", api.APISessionRequired(GetLicenseExpandStatus)).Methods("GET")
|
||||
api.BaseRoutes.Cloud.Handle("/subscription", api.APISessionRequired(changeSubscription)).Methods("PUT")
|
||||
|
||||
// GET /api/v4/cloud/request-trial
|
||||
@@ -413,6 +414,34 @@ func getCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func GetLicenseExpandStatus(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageLicenseInformation) {
|
||||
c.SetPermissionError(model.PermissionManageLicenseInformation)
|
||||
return
|
||||
}
|
||||
|
||||
_, token, err := c.App.Srv().GenerateLicenseRenewalLink()
|
||||
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
res, cloudErr := c.App.Cloud().GetLicenseExpandStatus(c.AppContext.Session().UserId, token)
|
||||
if cloudErr != nil {
|
||||
c.Err = model.NewAppError("Api4.GetLicenseExpandStatusForSubscription", "api.cloud.request_error", nil, "", http.StatusInternalServerError).Wrap(cloudErr)
|
||||
return
|
||||
}
|
||||
|
||||
json, jsonErr := json.Marshal(res)
|
||||
if jsonErr != nil {
|
||||
c.Err = model.NewAppError("Api4.GetLicenseExpandStatusForSubscription", "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func updateCloudCustomer(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !c.App.Channels().License().IsCloud() {
|
||||
c.Err = model.NewAppError("Api4.updateCloudCustomer", "api.cloud.license_error", nil, "", http.StatusForbidden)
|
||||
|
||||
@@ -649,6 +649,58 @@ func TestGetCloudProducts(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetExpandStatsForSubscription(t *testing.T) {
|
||||
isExpandable := &model.SubscriptionExpandStatus{
|
||||
IsExpandable: true,
|
||||
}
|
||||
|
||||
licenseId := "licenseID"
|
||||
|
||||
t.Run("NON Admin users are UNABLE to request expand stats for the subscription", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
||||
|
||||
cloud := mocks.CloudInterface{}
|
||||
|
||||
cloud.Mock.On("GetLicenseExpandStatus", mock.Anything).Return(isExpandable, nil)
|
||||
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = &cloud
|
||||
|
||||
subscriptionExpandable, r, err := th.Client.GetExpandStats(licenseId)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, subscriptionExpandable)
|
||||
require.Equal(t, http.StatusForbidden, r.StatusCode, "403 Forbidden")
|
||||
})
|
||||
|
||||
t.Run("Admin users are UNABLE to request licenses is expendable due missing the id", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
th.Client.Login(th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
||||
|
||||
cloud := mocks.CloudInterface{}
|
||||
|
||||
cloud.Mock.On("GetLicenseExpandStatus", mock.Anything).Return(isExpandable, nil)
|
||||
|
||||
cloudImpl := th.App.Srv().Cloud
|
||||
defer func() {
|
||||
th.App.Srv().Cloud = cloudImpl
|
||||
}()
|
||||
th.App.Srv().Cloud = &cloud
|
||||
|
||||
subscriptionExpandable, r, err := th.Client.GetExpandStats("")
|
||||
require.Error(t, err)
|
||||
require.Nil(t, subscriptionExpandable)
|
||||
require.Equal(t, http.StatusBadRequest, r.StatusCode, "400 Bad Request")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSelfHostedProducts(t *testing.T) {
|
||||
products := []*model.Product{
|
||||
{
|
||||
|
||||
@@ -398,8 +398,15 @@ func (a *App) buildUserNotifyProps(notifyProps model.StringMap) *imports.UserNot
|
||||
func (a *App) exportAllPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]imports.AttachmentImportData, *model.AppError) {
|
||||
var attachments []imports.AttachmentImportData
|
||||
afterId := strings.Repeat("0", 26)
|
||||
var postProcessCount uint64
|
||||
logCheckpoint := time.Now()
|
||||
|
||||
for {
|
||||
if time.Since(logCheckpoint) > 5*time.Minute {
|
||||
ctx.Logger().Debug(fmt.Sprintf("Bulk Export: processed %d posts", postProcessCount))
|
||||
logCheckpoint = time.Now()
|
||||
}
|
||||
|
||||
posts, nErr := a.Srv().Store().Post().GetParentsForExportAfter(1000, afterId)
|
||||
if nErr != nil {
|
||||
return nil, model.NewAppError("exportAllPosts", "app.post.get_posts.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
|
||||
@@ -411,6 +418,7 @@ func (a *App) exportAllPosts(ctx request.CTX, writer io.Writer, withAttachments
|
||||
|
||||
for _, post := range posts {
|
||||
afterId = post.Id
|
||||
postProcessCount++
|
||||
|
||||
// Skip deleted.
|
||||
if post.DeleteAt != 0 {
|
||||
@@ -677,7 +685,15 @@ func (a *App) buildFavoritedByList(channelID string) ([]string, *model.AppError)
|
||||
func (a *App) exportAllDirectPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]imports.AttachmentImportData, *model.AppError) {
|
||||
var attachments []imports.AttachmentImportData
|
||||
afterId := strings.Repeat("0", 26)
|
||||
var postProcessCount uint64
|
||||
logCheckpoint := time.Now()
|
||||
|
||||
for {
|
||||
if time.Since(logCheckpoint) > 5*time.Minute {
|
||||
ctx.Logger().Debug(fmt.Sprintf("Bulk Export: processed %d direct posts", postProcessCount))
|
||||
logCheckpoint = time.Now()
|
||||
}
|
||||
|
||||
posts, err := a.Srv().Store().Post().GetDirectPostParentsForExportAfter(1000, afterId)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("exportAllDirectPosts", "app.post.get_direct_posts.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
@@ -689,6 +705,7 @@ func (a *App) exportAllDirectPosts(ctx request.CTX, writer io.Writer, withAttach
|
||||
|
||||
for _, post := range posts {
|
||||
afterId = post.Id
|
||||
postProcessCount++
|
||||
|
||||
// Skip deleted.
|
||||
if post.DeleteAt != 0 {
|
||||
|
||||
@@ -17,6 +17,7 @@ type CloudInterface interface {
|
||||
ConfirmCustomerPayment(userID string, confirmRequest *model.ConfirmPaymentMethodRequest) error
|
||||
|
||||
GetCloudCustomer(userID string) (*model.CloudCustomer, error)
|
||||
GetLicenseExpandStatus(userID string, token string) (*model.SubscriptionExpandStatus, error)
|
||||
UpdateCloudCustomer(userID string, customerInfo *model.CloudCustomerInfo) (*model.CloudCustomer, error)
|
||||
UpdateCloudCustomerAddress(userID string, address *model.Address) (*model.CloudCustomer, error)
|
||||
|
||||
|
||||
@@ -325,6 +325,29 @@ func (_m *CloudInterface) GetInvoicesForSubscription(userID string) ([]*model.In
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetLicenseExpandStatus provides a mock function with given fields: userID, token
|
||||
func (_m *CloudInterface) GetLicenseExpandStatus(userID string, token string) (*model.SubscriptionExpandStatus, error) {
|
||||
ret := _m.Called(userID, token)
|
||||
|
||||
var r0 *model.SubscriptionExpandStatus
|
||||
if rf, ok := ret.Get(0).(func(string, string) *model.SubscriptionExpandStatus); ok {
|
||||
r0 = rf(userID, token)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.SubscriptionExpandStatus)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(userID, token)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetLicenseRenewalStatus provides a mock function with given fields: userID, token
|
||||
func (_m *CloudInterface) GetLicenseRenewalStatus(userID string, token string) error {
|
||||
ret := _m.Called(userID, token)
|
||||
|
||||
@@ -1887,14 +1887,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Изтече времето на AD/LDAP задачата за синхронизация."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Не може да се анализира заданието за износ на съобщения ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Не може да се анализира заданието за износ на съобщения BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "Лицензът ви не поддържа ID заредени изскачащи известия."
|
||||
|
||||
@@ -6355,14 +6355,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "AD/LDAP-Synchronisierungs-Job-Timeout erreicht."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Konnte ExportFromTimestamp des Nachrichten-Export-Jobs nicht verarbeiten."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Konnte BatchSize des Nachrichten-Export-Jobs nicht verarbeiten."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Cluster-API-Endpunkt nicht gefunden."
|
||||
|
||||
@@ -7595,14 +7595,6 @@
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "Your license does not support ID Loaded Push Notifications."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Could not parse message export job BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Could not parse message export job ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Reached AD/LDAP synchronization job timeout."
|
||||
|
||||
@@ -3251,14 +3251,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Reached AD/LDAP synchronisation job timeout."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Could not parse message export job ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Could not parse message export job BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "Your licence does not support ID Loaded Push Notifications."
|
||||
@@ -9693,5 +9685,9 @@
|
||||
{
|
||||
"id": "api.user.get_users.validation.app_error",
|
||||
"translation": "Error fetching roles during validation."
|
||||
},
|
||||
{
|
||||
"id": "api.server.hosted_signup_unavailable.error",
|
||||
"translation": "Portal unavailable for self-hosted signup."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6571,14 +6571,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "El tiempo de espera del trabajo de sincronización AD/LDAP fue alcanzado."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "No se pudo interpretar la fecha y hora de inicio de la exportación de mensajes."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "No se pudo interpretar el tamaño de bloque de datos de la exportación de mensajes."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "No se encontró el endpoint del API para el agrupamiento de servidores."
|
||||
|
||||
@@ -1919,14 +1919,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "مهلت زمانی هماهنگ سازی AD/LDAP رسیده است."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "تجزیه و تحلیل کار صادرات پیام ExportFromTimestamp امکان پذیر نیست."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "تجزیه و تحلیل کار صادرات پیام صادرات از مهر زمان انجام نمی شود.."
|
||||
},
|
||||
{
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "مجوز شما از ID Loaded Push Notifications پشتیبانی نمی کند."
|
||||
|
||||
@@ -6343,14 +6343,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Temps d'attente pour la tâche de synchronisation AD/LDAP atteint."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Impossible d'interpréter le paramètre ExportFromTimestamp de la tâche d'exportation de messages."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Impossible d'interpréter le paramètre BatchSize de la tâche d'exportation de messages."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Le nœud d'API cluster est introuvable."
|
||||
|
||||
@@ -3291,14 +3291,6 @@
|
||||
"id": "model.upload_session.is_valid.id.app_error",
|
||||
"translation": "Érvénytelen érték a Id -nak"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Nem sikerült feldolgozni az üzenet export munka ExportFromTimestamp értékét."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Nem sikerült feldolgozni az üzenet export BatchSize értékét."
|
||||
},
|
||||
{
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "Az Ön licensze nem támogatja az azonosítóval betöltött push értesítéseket."
|
||||
|
||||
@@ -6587,14 +6587,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Raggiunto timeout nel lavoro di sincronizzazione AD/LDAP."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Impossibile analizzare il messaggio del lavoro di esportazione ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Impossibile analizzare il messaggio del lavoro di esportazione BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Cluster API non trovate."
|
||||
|
||||
@@ -6563,14 +6563,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "AD/LDAP同期処理がタイムアウトしました。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "メッセージエクスポートジョブのExportFromTimestampを解析できませんでした。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "メッセージエクスポートジョブのBatchSizeを解析できませんでした。"
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "クラスターAPIエンドポイントが見つかりませんでした。"
|
||||
|
||||
94
i18n/ko.json
94
i18n/ko.json
@@ -6519,14 +6519,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Reached AD/LDAP synchronization job timeout."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Could not parse message export job ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Could not parse message export job BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Cluster API endpoint not found."
|
||||
@@ -7929,7 +7921,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.cloud.delinquency_email.missing_email_to_trigger",
|
||||
"translation": "연체 이메일을 보내기 위한 필수 항목이 누락되었습니다."
|
||||
"translation": "연체 알림 전자우편을 보내기 위한 필수 항목이 누락되었습니다."
|
||||
},
|
||||
{
|
||||
"id": "api.error_set_first_admin_complete_setup",
|
||||
@@ -7958,5 +7950,89 @@
|
||||
{
|
||||
"id": "sharedchannel.cannot_deliver_post",
|
||||
"translation": "{{.Remote}} 원격 사이트가 오프라인이기 때문에 하나 또는 그 이상의 포스트가 전송되지 않았습니다. 포스트는 해당 사이트가 온라인일 때 전송될 것입니다."
|
||||
},
|
||||
{
|
||||
"id": "app.notification.body.thread.title",
|
||||
"translation": "{{.SenderName}}님이 글타래에 답장을 남겼습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.notification.body.thread_channel.subTitle",
|
||||
"translation": "자리를 비운 동안, {{.SenderName}}님이 지켜보는 중인 글타래에 답장을 남겼습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.notification.body.thread_channel_full.subTitle",
|
||||
"translation": "자리를 비운 동안, {{.SenderName}}님이 {{.ChannelName}} 채널에 있는 지켜보는 중인 글타래에 답장을 남겼습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.notification.body.thread_gm.subTitle",
|
||||
"translation": "자리를 비운 동안, {{.SenderName}}님이 그룹 글타래에 답장을 남겼습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.notification.body.thread_dm.subTitle",
|
||||
"translation": "자리를 비운 동안, {{.SenderName}}님이 당신이 직접 보낸 메시지에 답장을 남겼습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.channel.autofollow.app_error",
|
||||
"translation": "언급된 사용자의 글타래 권한을 갱신하지 못했습니다"
|
||||
},
|
||||
{
|
||||
"id": "api.getThreadsForUser.bad_params",
|
||||
"translation": "getThreadsForUser의 Before와 After 매개변수는 상호 배타적입니다"
|
||||
},
|
||||
{
|
||||
"id": "api.getThreadsForUser.bad_only_params",
|
||||
"translation": "getThreadsForUser의 OnlyThreads와 OnlyTotals 매개변수는 상호 배타적입니다"
|
||||
},
|
||||
{
|
||||
"id": "app.post.get_top_threads_for_team_since.app_error",
|
||||
"translation": "팀의 상위 글타래를 가져올 수 없습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.post.get_top_threads_for_user_since.app_error",
|
||||
"translation": "사용자의 상위 글타래를 가져올 수 없습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.user.get_thread_count_for_user.app_error",
|
||||
"translation": "사용자의 글타래 개수를 가져올 수 없습니다."
|
||||
},
|
||||
{
|
||||
"id": "app.user.get_thread_membership_for_user.app_error",
|
||||
"translation": "사용자 글타래 권한을 가져올 수 없습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.get_thread_membership_for_user.not_found",
|
||||
"translation": "사용자 글타래 권한이 없습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.get_threads_for_user.app_error",
|
||||
"translation": "사용자 글타래들을 가져올 수 없습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.get_threads_for_user.not_found",
|
||||
"translation": "사용자 글타래가 존재하지 않거나 지켜보고 있지 않습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.update_thread_follow_for_user.app_error",
|
||||
"translation": "글타래의 지켜보기 상태를 갱신할 수 없습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.update_thread_read_for_user.app_error",
|
||||
"translation": "글타래의 읽음 상태를 갱신할 수 없습니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.update_thread_read_for_user_by_post.app_error",
|
||||
"translation": "유효하지 않은 post_id"
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.collapsed_threads.app_error",
|
||||
"translation": "CollapsedThreads 설정은 disabled, default_on 혹은 default_off 중 하나여야만 합니다"
|
||||
},
|
||||
{
|
||||
"id": "model.config.is_valid.collapsed_threads.autofollow.app_error",
|
||||
"translation": "CollapsedThreads 기능을 활성화하려면 ThreadAutoFollow 기능이 활성화되어야 합니다"
|
||||
},
|
||||
{
|
||||
"id": "app.user.update_threads_read_for_user.app_error",
|
||||
"translation": "모든 사용자 글타래들을 읽음 상태로 변경할 수 없습니다"
|
||||
}
|
||||
]
|
||||
|
||||
190
i18n/nl.json
190
i18n/nl.json
@@ -4769,7 +4769,7 @@
|
||||
},
|
||||
{
|
||||
"id": "web.error.unsupported_browser.min_os_version.mac",
|
||||
"translation": "macOS 10.14+"
|
||||
"translation": "macOS 11+"
|
||||
},
|
||||
{
|
||||
"id": "web.error.unsupported_browser.min_browser_version.safari",
|
||||
@@ -6603,14 +6603,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Time-out voor synchronisatie van AD/LDAP werd bereikt."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Fout bij het verwerken van bericht export taak ExportFromTimeStamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Fout bij ontleden van bericht exporttaak BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Cluster API endpoint niet gevonden."
|
||||
@@ -9264,7 +9256,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_14.subject",
|
||||
"translation": "Betaling is overtijd voor jouw Mattermost {{.Plan}}."
|
||||
"translation": "Betaling is laattijdig voor jouw Mattermost {{.Plan}}"
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_14.button",
|
||||
@@ -9300,7 +9292,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_7.subtitle1",
|
||||
"translation": "We konden jouw laatste betaling niet verwerken"
|
||||
"translation": "We konden jouw laatste betaling niet verwerken."
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_7.button",
|
||||
@@ -9348,7 +9340,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_45.subtitle1",
|
||||
"translation": "We hebben geen betaling kunnen innen voor openstaande facturen van {{.DelinquencyDate}}. Jouw werkruimte loopt het risico om gedowngraded te worden."
|
||||
"translation": "We hebben geen betaling kunnen innen voor openstaande facturen vanaf {{.DelinquencyDate}}. Jouw werkruimte loopt het risico om gedowngraded te worden."
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_45.subject",
|
||||
@@ -9364,7 +9356,7 @@
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_30.subtitle2",
|
||||
"translation": "als geen actie wordt ondernomen, zal jouw werkruimte worden gedowngraded en kunnen de volgende gegevens worden gearchiveerd:"
|
||||
"translation": "Als er geen actie wordt ondernomen, zal jouw werkruimte worden gedowngraded en kunnen de volgende gegevens worden gearchiveerd:"
|
||||
},
|
||||
{
|
||||
"id": "api.templates.delinquency_30.subtitle1",
|
||||
@@ -9561,5 +9553,177 @@
|
||||
{
|
||||
"id": "api.admin.syncables_error",
|
||||
"translation": "kon gebruiker niet toevoegen aan groep-teams en groep-kanalen"
|
||||
},
|
||||
{
|
||||
"id": "api.acknowledgement.save.archived_channel.app_error",
|
||||
"translation": "Je kan niet bevestigen in een gearchiveerd kanaal."
|
||||
},
|
||||
{
|
||||
"id": "api.acknowledgement.delete.deadline.app_error",
|
||||
"translation": "Je kan een bevestiging niet wissen nadat 5min verstreken zijn."
|
||||
},
|
||||
{
|
||||
"id": "api.acknowledgement.delete.archived_channel.app_error",
|
||||
"translation": "Je kan een bevestiging in een gearchiveerd kanaal niet verwijderen."
|
||||
},
|
||||
{
|
||||
"id": "worktemplate.product_teams.feature_release.description.playbook",
|
||||
"translation": "Creëer transparante workflows tussen ontwikkelingsteams om ervoor te zorgen dat jouw ontwikkelingsproces naadloos verloopt."
|
||||
},
|
||||
{
|
||||
"id": "worktemplate.product_teams.feature_release.description.integration",
|
||||
"translation": "Verhoog de productiviteit in je kanaal door een Jira bot en Github bot te integreren. Deze worden voor jou gedownload."
|
||||
},
|
||||
{
|
||||
"id": "worktemplate.product_teams.feature_release.description.channel",
|
||||
"translation": "Chat met je team in een Feature Release-kanaal dat gemakkelijk verbinding maakt met je boards, playbooks en app bots."
|
||||
},
|
||||
{
|
||||
"id": "worktemplate.product_teams.feature_release.description.board",
|
||||
"translation": "Gebruik ons vergaderagenda-bord voor terugkerende vergaderingen zoals stand-up en ons Projecttakenbord om de voortgang van taken onderweg te beheren."
|
||||
},
|
||||
{
|
||||
"id": "worktemplate.category.product_teams",
|
||||
"translation": "Productteams"
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.user_id.app_error",
|
||||
"translation": "Ongeldig gebruikers-id."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.update_at.app_error",
|
||||
"translation": "Het veld 'update at' moet een geldige tijd zijn."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.root_id.app_error",
|
||||
"translation": "Ongeldig root id."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.props.app_error",
|
||||
"translation": "Ongeldige eigenschappen."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.priority.app_error",
|
||||
"translation": "Ongeldige prioriteit"
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.msg.app_error",
|
||||
"translation": "Ongeldig bericht."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.file_ids.app_error",
|
||||
"translation": "Ongeldige bestandids."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.create_at.app_error",
|
||||
"translation": "Create at moet een geldige tijd zijn."
|
||||
},
|
||||
{
|
||||
"id": "model.acknowledgement.is_valid.user_id.app_error",
|
||||
"translation": "Ongeldig gebruikersid."
|
||||
},
|
||||
{
|
||||
"id": "model.draft.is_valid.channel_id.app_error",
|
||||
"translation": "Ongeldig kanaalid."
|
||||
},
|
||||
{
|
||||
"id": "model.acknowledgement.is_valid.post_id.app_error",
|
||||
"translation": "Ongeldig bericht-id."
|
||||
},
|
||||
{
|
||||
"id": "app.worktemplates.get_templates.app_error",
|
||||
"translation": "Kon geen werksjablonen ophalen"
|
||||
},
|
||||
{
|
||||
"id": "app.worktemplates.get_categories.app_error",
|
||||
"translation": "Kan geen werksjablooncategorieën ophalen"
|
||||
},
|
||||
{
|
||||
"id": "app.post_prority.get_for_post.app_error",
|
||||
"translation": "Kon geen berichtprioriteit ophalen voor bericht"
|
||||
},
|
||||
{
|
||||
"id": "app.draft.update.app_error",
|
||||
"translation": "Kan het concept niet bijwerken."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.save.app_error",
|
||||
"translation": "Kan het concept niet opslaan."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.get_for_draft.app_error",
|
||||
"translation": "Kan geen bestanden ophalen voor concept."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.get_drafts.app_error",
|
||||
"translation": "Kon de Concepten van de gebruiker niet ophalen."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.get.app_error",
|
||||
"translation": "Kon het concept niet ophalen."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.feature_disabled",
|
||||
"translation": "De Conceptfunctie is uitgeschakeld."
|
||||
},
|
||||
{
|
||||
"id": "app.draft.delete.app_error",
|
||||
"translation": "Kan het concept niet verwijderen."
|
||||
},
|
||||
{
|
||||
"id": "app.channel.get_priority_for_posts.app_error",
|
||||
"translation": "Fout bij het ophalen van de prioriteiten voor berichten"
|
||||
},
|
||||
{
|
||||
"id": "app.channel.count_urgent_posts_since.app_error",
|
||||
"translation": "Fout bij het tellen van de dringende berichten sinds de opgegeven datum."
|
||||
},
|
||||
{
|
||||
"id": "app.acknowledgement.save.save.app_error",
|
||||
"translation": "Fout hij het bewaren van de bevestiging voor het bericht."
|
||||
},
|
||||
{
|
||||
"id": "app.acknowledgement.getforpost.get.app_error",
|
||||
"translation": "Fout hij het ophalen van de bevestiging voor bericht."
|
||||
},
|
||||
{
|
||||
"id": "app.acknowledgement.get.app_error",
|
||||
"translation": "Fout hij het ophalen van de bevestiging."
|
||||
},
|
||||
{
|
||||
"id": "app.acknowledgement.delete.app_error",
|
||||
"translation": "Kan bevestiging niet verwijderen."
|
||||
},
|
||||
{
|
||||
"id": "api.user.get_users.validation.app_error",
|
||||
"translation": "Fout bij het ophalen van rollen tijdens de validatie."
|
||||
},
|
||||
{
|
||||
"id": "api.upload.create.upload_too_large.app_error",
|
||||
"translation": "Kan bestand niet uploaden. Bestand is te groot."
|
||||
},
|
||||
{
|
||||
"id": "api.templates.cloud_welcome_email.yearly_plan_button",
|
||||
"translation": "Bekijk jouw factuur"
|
||||
},
|
||||
{
|
||||
"id": "api.templates.cloud_upgrade_confirmation_yearly.subtitle",
|
||||
"translation": "Jouw {{.WorkspaceName}} werkruimte is nu opgewaardeerd."
|
||||
},
|
||||
{
|
||||
"id": "api.templates.cloud_upgrade_confirmation_monthly.subtitle",
|
||||
"translation": "Jouw {{.WorkspaceName}} werkruimte is nu geüpgraded. Dit zal gefactureerd worden vanaf {{.Date}}"
|
||||
},
|
||||
{
|
||||
"id": "api.server.hosted_signup_unavailable.error",
|
||||
"translation": "Portaal niet beschikbaar voor self-hosted signup."
|
||||
},
|
||||
{
|
||||
"id": "api.drafts.disabled.app_error",
|
||||
"translation": "De Conceptfunctie is uitgeschakeld."
|
||||
},
|
||||
{
|
||||
"id": "api.draft.create_draft.can_not_draft_to_deleted.error",
|
||||
"translation": "Kan concept niet bewaren in een verwijderd kanaal"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6351,14 +6351,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Osiągnięto limit czasu zadania synchronizacji AD/LDAP."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Nie można przeanalizować zadania eksportowania komunikatu ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Nie można przeanalizować zadania eksportu komunikatu BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Nie znaleziono punktu końcowego interfejsu API klastra."
|
||||
|
||||
@@ -6571,14 +6571,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Tarefa de sincronização do AD/LDAP alcançou o limite de tempo."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Não foi possível analisar a tarefa de exportação de mensagens ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Não foi possível analisar a tarefa de exportação de mensagens BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Endpoint Cluster API não encontrado."
|
||||
|
||||
@@ -6619,14 +6619,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Am atins intervalul de timp pentru lucrarea de sincronizare AD/LDAP."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Ar putea analiza mesaj export job ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Ar putea analiza mesaj export job BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Clustering API final nu a fost găsit."
|
||||
|
||||
@@ -6615,14 +6615,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Достигнут тайм-аут задания синхронизации AD/LDAP."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Не удалось разобрать задание экспорта сообщения ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Не удалось проанализировать задание экспорта сообщения BatchSize."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Не найдена конечная точка API кластера."
|
||||
|
||||
12
i18n/sv.json
12
i18n/sv.json
@@ -3039,14 +3039,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Nådde timeout för AD/LDAP-synkronisering."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Kunde inte tolka värdet ExportFromTimestamp i export job."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Kunde inte tolka värdet BatchSize i export job."
|
||||
},
|
||||
{
|
||||
"id": "ent.id_loaded.license_disable.app_error",
|
||||
"translation": "Din licens tillåter inte pushnotifiering via meddelande-ID."
|
||||
@@ -9729,5 +9721,9 @@
|
||||
{
|
||||
"id": "model.draft.is_valid.props.app_error",
|
||||
"translation": "Ogiltiga attribut."
|
||||
},
|
||||
{
|
||||
"id": "api.server.hosted_signup_unavailable.error",
|
||||
"translation": "Portalen är inte tillgänglig för egen-hostad registrering."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6603,14 +6603,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "AD/LDAP eşitleme görevi zaman aşımına uğradı."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "İleti dışa aktarma görevinde ExportFromTimestamp değeri çözümlenemedi."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "İleti dışa aktarma görevinde BatchSize değeri çözümlenemedi."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Küme API uç noktası bulunamadı."
|
||||
|
||||
@@ -6335,14 +6335,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "Досягнута тайм-аут завдання синхронізації AD / LDAP."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "Не вдалося проаналізувати завдання експортування повідомлень ExportFromTimestamp."
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "Не вдалося проаналізувати BatchSize завдання експортування повідомлення."
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "Не знайдена кінцева точка API кластера."
|
||||
|
||||
@@ -6479,14 +6479,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "AD/LDAP 同步任务超时。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "无法解析 ExportFromTimestamp 导出任务消息。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "无法解析 BatchSize 导出任务消息。"
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "未找到机群 API 接口。"
|
||||
|
||||
@@ -6539,14 +6539,6 @@
|
||||
"id": "ent.jobs.start_synchronize_job.timeout",
|
||||
"translation": "AD/LDAP 同步工作逾時。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_start_timestamp.parse_error",
|
||||
"translation": "無法解析訊息匯出工作 ExportFromTimestamp。"
|
||||
},
|
||||
{
|
||||
"id": "ent.jobs.do_job.batch_size.parse_error",
|
||||
"translation": "無法解析訊息匯出工作 BatchSize。"
|
||||
},
|
||||
{
|
||||
"id": "ent.cluster.404.app_error",
|
||||
"translation": "找不到叢集 API 端點。"
|
||||
|
||||
@@ -55,7 +55,8 @@ func MakeWorker(jobServer *jobs.JobServer, app AppIface) model.Worker {
|
||||
}
|
||||
}()
|
||||
|
||||
appErr := app.BulkExport(request.EmptyContext(app.Log()), wr, outPath, opts)
|
||||
logger := app.Log().With(mlog.String("job_id", job.Id))
|
||||
appErr := app.BulkExport(request.EmptyContext(logger), wr, outPath, opts)
|
||||
wr.Close() // Close never returns an error
|
||||
|
||||
if appErr != nil {
|
||||
|
||||
@@ -8213,6 +8213,19 @@ func (c *Client4) GetCloudCustomer() (*CloudCustomer, *Response, error) {
|
||||
return cloudCustomer, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetExpandStats(licenseId string) (*SubscriptionExpandStatus, *Response, error) {
|
||||
r, err := c.DoAPIGet(fmt.Sprintf("%s%s?licenseID=%s", c.cloudRoute(), "/subscription/expand", licenseId), "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
|
||||
var subscriptionExpandable *SubscriptionExpandStatus
|
||||
json.NewDecoder(r.Body).Decode(&subscriptionExpandable)
|
||||
|
||||
return subscriptionExpandable, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetSubscription() (*Subscription, *Response, error) {
|
||||
r, err := c.DoAPIGet(c.cloudRoute()+"/subscription", "")
|
||||
if err != nil {
|
||||
|
||||
@@ -124,6 +124,10 @@ type ValidateBusinessEmailResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
}
|
||||
|
||||
type SubscriptionExpandStatus struct {
|
||||
IsExpandable bool `json:"is_expandable"`
|
||||
}
|
||||
|
||||
// CloudCustomerInfo represents editable info of a customer.
|
||||
type CloudCustomerInfo struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -333,13 +333,16 @@ type GetPostsOptions struct {
|
||||
|
||||
type PostCountOptions struct {
|
||||
// Only include posts on a specific team. "" for any team.
|
||||
TeamId string
|
||||
MustHaveFile bool
|
||||
MustHaveHashtag bool
|
||||
ExcludeDeleted bool
|
||||
UsersPostsOnly bool
|
||||
TeamId string
|
||||
MustHaveFile bool
|
||||
MustHaveHashtag bool
|
||||
ExcludeDeleted bool
|
||||
ExcludeSystemPosts bool
|
||||
UsersPostsOnly bool
|
||||
// AllowFromCache looks up cache only when ExcludeDeleted and UsersPostsOnly are true and rest are falsy.
|
||||
AllowFromCache bool
|
||||
SincePostID string
|
||||
SinceUpdateAt int64
|
||||
}
|
||||
|
||||
func (o *Post) Etag() string {
|
||||
|
||||
@@ -209,4 +209,5 @@ type BoardsService interface {
|
||||
PatchCard(cardPatch *fb_model.CardPatch, cardID string, userID string) (*fb_model.Card, error)
|
||||
DeleteCard(cardID string, userID string) error
|
||||
HasPermissionToBoard(userID, boardID string, permission *model.Permission) bool
|
||||
DuplicateBoard(boardID string, userID string, toTeam string, asTemplate bool) (*fb_model.BoardsAndBlocks, []*fb_model.BoardMember, error)
|
||||
}
|
||||
|
||||
@@ -2272,6 +2272,20 @@ func (s *SqlPostStore) AnalyticsPostCount(options *model.PostCountOptions) (int6
|
||||
query = query.Where(sq.Eq{"p.DeleteAt": 0})
|
||||
}
|
||||
|
||||
if options.ExcludeSystemPosts {
|
||||
query = query.Where("p.Type NOT LIKE 'system_%'")
|
||||
}
|
||||
|
||||
if options.SinceUpdateAt > 0 {
|
||||
query = query.Where(sq.Or{
|
||||
sq.Gt{"p.UpdateAt": options.SinceUpdateAt},
|
||||
sq.And{
|
||||
sq.Eq{"p.UpdateAt": options.SinceUpdateAt},
|
||||
sq.Gt{"p.Id": options.SincePostID},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "post_tosql")
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetPostBeforeAfter", func(t *testing.T) { testPostStoreGetPostBeforeAfter(t, ss) })
|
||||
t.Run("UserCountsWithPostsByDay", func(t *testing.T) { testUserCountsWithPostsByDay(t, ss) })
|
||||
t.Run("PostCountsByDuration", func(t *testing.T) { testPostCountsByDay(t, ss) })
|
||||
t.Run("PostCounts", func(t *testing.T) { testPostCounts(t, ss) })
|
||||
t.Run("GetFlaggedPostsForTeam", func(t *testing.T) { testPostStoreGetFlaggedPostsForTeam(t, ss, s) })
|
||||
t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
|
||||
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
|
||||
@@ -2685,45 +2686,169 @@ func testPostCountsByDay(t *testing.T, ss store.Store) {
|
||||
r1, err = ss.Post().AnalyticsPostCountsByDay(postCountsOptions)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, float64(1), r1[0].Value)
|
||||
}
|
||||
|
||||
func testPostCounts(t *testing.T, ss store.Store) {
|
||||
now := time.Now()
|
||||
twentyMinAgo := now.Add(-20 * time.Minute).UnixMilli()
|
||||
fifteenMinAgo := now.Add(-15 * time.Minute).UnixMilli()
|
||||
tenMinAgo := now.Add(-10 * time.Minute).UnixMilli()
|
||||
|
||||
t1 := &model.Team{}
|
||||
t1.DisplayName = "DisplayName"
|
||||
t1.Name = NewTestId()
|
||||
t1.Email = MakeEmail()
|
||||
t1.Type = model.TeamOpen
|
||||
t1, err := ss.Team().Save(t1)
|
||||
require.NoError(t, err)
|
||||
|
||||
c1 := &model.Channel{}
|
||||
c1.TeamId = t1.Id
|
||||
c1.DisplayName = "Channel2"
|
||||
c1.Name = NewTestId()
|
||||
c1.Type = model.ChannelTypeOpen
|
||||
c1, nErr := ss.Channel().Save(c1, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// system post
|
||||
p1 := &model.Post{}
|
||||
p1.Type = "system_add_to_channel"
|
||||
p1.ChannelId = c1.Id
|
||||
p1.UserId = model.NewId()
|
||||
p1.Message = NewTestId()
|
||||
p1.CreateAt = twentyMinAgo
|
||||
p1.UpdateAt = twentyMinAgo
|
||||
_, nErr = ss.Post().Save(p1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p2 := &model.Post{}
|
||||
p2.ChannelId = c1.Id
|
||||
p2.UserId = model.NewId()
|
||||
p2.Message = NewTestId()
|
||||
p2.Hashtags = "hashtag"
|
||||
p2.CreateAt = twentyMinAgo
|
||||
p2.UpdateAt = twentyMinAgo
|
||||
p2, nErr = ss.Post().Save(p2)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p3 := &model.Post{}
|
||||
p3.ChannelId = c1.Id
|
||||
p3.UserId = model.NewId()
|
||||
p3.Message = NewTestId()
|
||||
p3.FileIds = []string{"fileId1"}
|
||||
p3.CreateAt = twentyMinAgo
|
||||
p3.UpdateAt = twentyMinAgo
|
||||
_, nErr = ss.Post().Save(p3)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p4 := &model.Post{}
|
||||
p4.ChannelId = c1.Id
|
||||
p4.UserId = model.NewId()
|
||||
p4.Message = NewTestId()
|
||||
p4.Filenames = []string{"filename1"}
|
||||
p4.CreateAt = tenMinAgo
|
||||
p4.UpdateAt = tenMinAgo
|
||||
p4, nErr = ss.Post().Save(p4)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p5 := &model.Post{}
|
||||
p5.ChannelId = c1.Id
|
||||
p5.UserId = p4.UserId
|
||||
p5.Message = NewTestId()
|
||||
p5.Hashtags = "hashtag"
|
||||
p5.FileIds = []string{"fileId2"}
|
||||
p5.CreateAt = tenMinAgo
|
||||
p5.UpdateAt = tenMinAgo
|
||||
_, nErr = ss.Post().Save(p5)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
bot1 := &model.Bot{
|
||||
Username: "username",
|
||||
Description: "a bot",
|
||||
OwnerId: model.NewId(),
|
||||
UserId: model.NewId(),
|
||||
}
|
||||
_, nErr = ss.Bot().Save(bot1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p6 := &model.Post{}
|
||||
p6.Message = "bot message one"
|
||||
p6.ChannelId = c1.Id
|
||||
p6.UserId = bot1.UserId
|
||||
p6.CreateAt = twentyMinAgo
|
||||
p6.UpdateAt = twentyMinAgo
|
||||
_, nErr = ss.Post().Save(p6)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p7 := &model.Post{}
|
||||
p7.Message = "bot message two"
|
||||
p7.ChannelId = c1.Id
|
||||
p7.UserId = bot1.UserId
|
||||
p7.CreateAt = tenMinAgo
|
||||
p7.UpdateAt = tenMinAgo
|
||||
_, nErr = ss.Post().Save(p7)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// total across all teams
|
||||
c, err := ss.Post().AnalyticsPostCount(&model.PostCountOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, c, int64(7))
|
||||
|
||||
// total for single team
|
||||
r2, err := ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id})
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(6), r2)
|
||||
assert.Equal(t, int64(7), c)
|
||||
|
||||
// total across teams
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{})
|
||||
// with files
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, MustHaveFile: true})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, r2, int64(6))
|
||||
assert.Equal(t, int64(3), c)
|
||||
|
||||
// total across teams with files
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{MustHaveFile: true})
|
||||
// with hashtags
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, MustHaveHashtag: true})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, r2, int64(3))
|
||||
assert.Equal(t, int64(2), c)
|
||||
|
||||
// total across teams with hashtags
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{MustHaveHashtag: true})
|
||||
// with hashtags and files
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, MustHaveFile: true, MustHaveHashtag: true})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, r2, int64(2))
|
||||
assert.Equal(t, int64(1), c)
|
||||
|
||||
// total across teams with hashtags and files
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{MustHaveFile: true, MustHaveHashtag: true})
|
||||
// excluding system posts
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, ExcludeSystemPosts: true})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, r2, int64(1))
|
||||
assert.Equal(t, int64(6), c)
|
||||
|
||||
// before update_at time
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, SinceUpdateAt: fifteenMinAgo})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), c)
|
||||
|
||||
// equal to update_at time
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, SinceUpdateAt: tenMinAgo})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), c)
|
||||
|
||||
// since update_at and since post id
|
||||
tenMinAgoIDs := []string{p4.Id, p5.Id, p7.Id}
|
||||
sort.Strings(tenMinAgoIDs)
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, SinceUpdateAt: tenMinAgo, SincePostID: tenMinAgoIDs[0]})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), c)
|
||||
|
||||
// delete 1 post
|
||||
err = ss.Post().Delete(o1.Id, 1, o1.UserId)
|
||||
err = ss.Post().Delete(p2.Id, 1, p2.UserId)
|
||||
require.NoError(t, err)
|
||||
|
||||
// total for single team with the deleted post excluded
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, ExcludeDeleted: true})
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, ExcludeDeleted: true})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), r2)
|
||||
assert.Equal(t, int64(6), c)
|
||||
|
||||
// total users only posts for single team with the deleted post excluded
|
||||
r2, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, ExcludeDeleted: true, UsersPostsOnly: true})
|
||||
c, err = ss.Post().AnalyticsPostCount(&model.PostCountOptions{TeamId: t1.Id, ExcludeDeleted: true, UsersPostsOnly: true})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), r2)
|
||||
assert.Equal(t, int64(3), c)
|
||||
}
|
||||
|
||||
func testPostStoreGetFlaggedPostsForTeam(t *testing.T, ss store.Store, s SqlStore) {
|
||||
|
||||
Ссылка в новой задаче
Block a user