Merge remote-tracking branch 'origin/master' into advanced-permissions-phase-2

Этот коммит содержится в:
Martin Kraft
2018-05-16 14:45:46 -04:00
родитель 16bbbc2abc 02f8c18f40
Коммит f1a830ce9a
41 изменённых файлов: 2481 добавлений и 2023 удалений

Просмотреть файл

@@ -277,7 +277,14 @@ store-mocks: ## Creates mock files.
ldap-mocks: ## Creates mock files for ldap. ldap-mocks: ## Creates mock files for ldap.
go get github.com/vektra/mockery/... go get github.com/vektra/mockery/...
GOPATH=$(shell go env GOPATH) $(shell go env GOPATH)/bin/mockery -dir enterprise/ldap -all -output enterprise/ldap/mocks -note 'Regenerate this file using `make ldap-mocks`.' $(GOPATH)/bin/mockery -dir enterprise/ldap -all -output enterprise/ldap/mocks -note 'Regenerate this file using `make ldap-mocks`.'
plugin-mocks: ## Creates mock files for plugins.
go get github.com/vektra/mockery/...
$(GOPATH)/bin/mockery -dir plugin -name API -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
$(GOPATH)/bin/mockery -dir plugin -name KeyValueStore -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
$(GOPATH)/bin/mockery -dir plugin -name Hooks -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
@sed -i'' -e 's|API|APIMOCKINTERNAL|g' plugin/plugintest/api.go
update-jira-plugin: ## Updates Jira plugin. update-jira-plugin: ## Updates Jira plugin.
go get github.com/mattermost/go-bindata/... go get github.com/mattermost/go-bindata/...

1698
NOTICE.txt

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@@ -227,6 +227,29 @@ func (me *TestHelper) createChannel(team *model.Team, channelType string) *model
return channel return channel
} }
func (me *TestHelper) createChannelWithAnotherUser(team *model.Team, channelType, userId string) *model.Channel {
id := model.NewId()
channel := &model.Channel{
DisplayName: "dn_" + id,
Name: "name_" + id,
Type: channelType,
TeamId: team.Id,
CreatorId: userId,
}
utils.DisableDebugLogForTest()
var err *model.AppError
if channel, err = me.App.CreateChannel(channel, true); err != nil {
mlog.Error(err.Error())
time.Sleep(time.Second)
panic(err)
}
utils.EnableDebugLogForTest()
return channel
}
func (me *TestHelper) CreateDmChannel(user *model.User) *model.Channel { func (me *TestHelper) CreateDmChannel(user *model.User) *model.Channel {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
var err *model.AppError var err *model.AppError

Просмотреть файл

@@ -79,10 +79,18 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} }
if channelToJoin.Type == model.CHANNEL_PRIVATE && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) { // Check if the user who wants to add another is trying to add in a pvt channel, but does not have permission
// but is in the channel
_, err = a.GetChannelMember(channelToJoin.Id, args.UserId)
if channelToJoin.Type == model.CHANNEL_PRIVATE && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) && err == nil {
return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} }
// In this case just check if is a pvt channel and user has permission
if channelToJoin.Type == model.CHANNEL_PRIVATE && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
return &model.CommandResponse{Text: args.T("api.command_invite.private_channel.app_error", map[string]interface{}{"Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
// Check if user is already in the channel // Check if user is already in the channel
_, err = a.GetChannelMember(channelToJoin.Id, userProfile.Id) _, err = a.GetChannelMember(channelToJoin.Id, userProfile.Id)
if err == nil { if err == nil {

Просмотреть файл

@@ -18,6 +18,7 @@ func TestInviteProvider(t *testing.T) {
channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN)
privateChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE) privateChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE)
dmChannel := th.CreateDmChannel(th.BasicUser2) dmChannel := th.CreateDmChannel(th.BasicUser2)
privateChannel2 := th.createChannelWithAnotherUser(th.BasicTeam, model.CHANNEL_PRIVATE, th.BasicUser2.Id)
basicUser3 := th.CreateUser() basicUser3 := th.CreateUser()
th.LinkUserToTeam(basicUser3, th.BasicTeam) th.LinkUserToTeam(basicUser3, th.BasicTeam)
@@ -36,6 +37,7 @@ func TestInviteProvider(t *testing.T) {
userAndDisplayChannel := "@" + th.BasicUser2.Username + " ~" + channel.DisplayName + " " userAndDisplayChannel := "@" + th.BasicUser2.Username + " ~" + channel.DisplayName + " "
userAndPrivateChannel := "@" + th.BasicUser2.Username + " ~" + privateChannel.Name userAndPrivateChannel := "@" + th.BasicUser2.Username + " ~" + privateChannel.Name
userAndDMChannel := "@" + basicUser3.Username + " ~" + dmChannel.Name userAndDMChannel := "@" + basicUser3.Username + " ~" + dmChannel.Name
userAndInvalidPrivate := "@" + basicUser3.Username + " ~" + privateChannel2.Name
tests := []struct { tests := []struct {
desc string desc string
@@ -97,6 +99,11 @@ func TestInviteProvider(t *testing.T) {
expected: "api.command_invite.directchannel.app_error", expected: "api.command_invite.directchannel.app_error",
msg: userAndDMChannel, msg: userAndDMChannel,
}, },
{
desc: "try to add a user to a privante channel with no permission",
expected: "api.command_invite.private_channel.app_error",
msg: userAndInvalidPrivate,
},
} }
for _, test := range tests { for _, test := range tests {

Просмотреть файл

@@ -217,7 +217,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
} }
if userAllowsEmails && status.Status != model.STATUS_ONLINE && profileMap[id].DeleteAt == 0 { if userAllowsEmails && status.Status != model.STATUS_ONLINE && profileMap[id].DeleteAt == 0 {
a.sendNotificationEmail(post, profileMap[id], channel, team, senderName, sender) a.sendNotificationEmail(post, profileMap[id], channel, team, channelName, senderName, sender)
} }
} }
} }
@@ -351,7 +351,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
return mentionedUsersList, nil return mentionedUsersList, nil
} }
func (a *App) sendNotificationEmail(post *model.Post, user *model.User, channel *model.Channel, team *model.Team, senderName string, sender *model.User) *model.AppError { func (a *App) sendNotificationEmail(post *model.Post, user *model.User, channel *model.Channel, team *model.Team, channelName string, senderName string, sender *model.User) *model.AppError {
if channel.IsGroupOrDirect() { if channel.IsGroupOrDirect() {
if result := <-a.Srv.Store.Team().GetTeamsByUserId(user.Id); result.Err != nil { if result := <-a.Srv.Store.Team().GetTeamsByUserId(user.Id); result.Err != nil {
return result.Err return result.Err
@@ -396,22 +396,24 @@ func (a *App) sendNotificationEmail(post *model.Post, user *model.User, channel
translateFunc := utils.GetUserTranslations(user.Locale) translateFunc := utils.GetUserTranslations(user.Locale)
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
if license := a.License(); license != nil && *license.Features.EmailNotificationContents {
emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType
}
var subjectText string var subjectText string
if channel.Type == model.CHANNEL_DIRECT { if channel.Type == model.CHANNEL_DIRECT {
subjectText = getDirectMessageNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, senderName) subjectText = getDirectMessageNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, senderName)
} else if channel.Type == model.CHANNEL_GROUP {
subjectText = getGroupMessageNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, channelName, emailNotificationContentsType)
} else if *a.Config().EmailSettings.UseChannelInEmailNotifications { } else if *a.Config().EmailSettings.UseChannelInEmailNotifications {
subjectText = getNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, team.DisplayName+" ("+channel.DisplayName+")") subjectText = getNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, team.DisplayName+" ("+channel.DisplayName+")")
} else { } else {
subjectText = getNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, team.DisplayName) subjectText = getNotificationEmailSubject(post, translateFunc, a.Config().TeamSettings.SiteName, team.DisplayName)
} }
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
if license := a.License(); license != nil && *license.Features.EmailNotificationContents {
emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType
}
teamURL := a.GetSiteURL() + "/" + team.Name teamURL := a.GetSiteURL() + "/" + team.Name
var bodyText = a.getNotificationEmailBody(user, post, channel, senderName, team.Name, teamURL, emailNotificationContentsType, translateFunc) var bodyText = a.getNotificationEmailBody(user, post, channel, channelName, senderName, team.Name, teamURL, emailNotificationContentsType, translateFunc)
a.Go(func() { a.Go(func() {
if err := a.SendMail(user.Email, html.UnescapeString(subjectText), bodyText); err != nil { if err := a.SendMail(user.Email, html.UnescapeString(subjectText), bodyText); err != nil {
@@ -456,10 +458,37 @@ func getNotificationEmailSubject(post *model.Post, translateFunc i18n.TranslateF
return translateFunc("app.notification.subject.notification.full", subjectParameters) return translateFunc("app.notification.subject.notification.full", subjectParameters)
} }
/**
* Computes the subject line for group email messages
*/
func getGroupMessageNotificationEmailSubject(post *model.Post, translateFunc i18n.TranslateFunc, siteName string, channelName string, emailNotificationContentsType string) string {
t := getFormattedPostTime(post, translateFunc)
var subjectText string
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
var subjectParameters = map[string]interface{}{
"SiteName": siteName,
"ChannelName": channelName,
"Month": t.Month,
"Day": t.Day,
"Year": t.Year,
}
subjectText = translateFunc("app.notification.subject.group_message.full", subjectParameters)
} else {
var subjectParameters = map[string]interface{}{
"SiteName": siteName,
"Month": t.Month,
"Day": t.Day,
"Year": t.Year,
}
subjectText = translateFunc("app.notification.subject.group_message.generic", subjectParameters)
}
return subjectText
}
/** /**
* Computes the email body for notification messages * Computes the email body for notification messages
*/ */
func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post, channel *model.Channel, senderName string, teamName string, teamURL string, emailNotificationContentsType string, translateFunc i18n.TranslateFunc) string { func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post, channel *model.Channel, channelName string, senderName string, teamName string, teamURL string, emailNotificationContentsType string, translateFunc i18n.TranslateFunc) string {
// only include message contents in notification email if email notification contents type is set to full // only include message contents in notification email if email notification contents type is set to full
var bodyPage *utils.HTMLTemplate var bodyPage *utils.HTMLTemplate
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL { if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
@@ -476,10 +505,6 @@ func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post,
bodyPage.Props["TeamLink"] = teamURL bodyPage.Props["TeamLink"] = teamURL
} }
var channelName = channel.DisplayName
if channel.Type == model.CHANNEL_GROUP {
channelName = translateFunc("api.templates.channel_name.group")
}
t := getFormattedPostTime(post, translateFunc) t := getFormattedPostTime(post, translateFunc)
var bodyText string var bodyText string
@@ -509,6 +534,32 @@ func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post,
"Day": t.Day, "Day": t.Day,
}) })
} }
} else if channel.Type == model.CHANNEL_GROUP {
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
bodyText = translateFunc("app.notification.body.intro.group_message.full")
info = utils.TranslateAsHtml(translateFunc, "app.notification.body.text.group_message.full",
map[string]interface{}{
"ChannelName": channelName,
"SenderName": senderName,
"Hour": t.Hour,
"Minute": t.Minute,
"TimeZone": t.TimeZone,
"Month": t.Month,
"Day": t.Day,
})
} else {
bodyText = translateFunc("app.notification.body.intro.group_message.generic", map[string]interface{}{
"SenderName": senderName,
})
info = utils.TranslateAsHtml(translateFunc, "app.notification.body.text.group_message.generic",
map[string]interface{}{
"Hour": t.Hour,
"Minute": t.Minute,
"TimeZone": t.TimeZone,
"Month": t.Month,
"Day": t.Day,
})
}
} else { } else {
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL { if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
bodyText = translateFunc("app.notification.body.intro.notification.full") bodyText = translateFunc("app.notification.body.intro.notification.full")
@@ -919,12 +970,13 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit
// remove trailing '.', as that is the end of a sentence // remove trailing '.', as that is the end of a sentence
foundWithSuffix := false foundWithSuffix := false
for _, suffixPunctuation := range []string{".", ":"} {
for strings.HasSuffix(word, ".") { for strings.HasSuffix(word, suffixPunctuation) {
word = strings.TrimSuffix(word, ".") word = strings.TrimSuffix(word, suffixPunctuation)
if checkForMention(word) { if checkForMention(word) {
foundWithSuffix = true foundWithSuffix = true
break break
}
} }
} }

Просмотреть файл

@@ -148,6 +148,16 @@ func TestGetExplicitMentions(t *testing.T) {
OtherPotentialMentions: []string{"user"}, OtherPotentialMentions: []string{"user"},
}, },
}, },
"OnePersonWithColonAtEnd": {
Message: "this is a message for @user:",
Keywords: map[string][]string{"this": {id1}},
Expected: &ExplicitMentions{
MentionedUserIds: map[string]bool{
id1: true,
},
OtherPotentialMentions: []string{"user"},
},
},
"MultiplePeopleWithOneWord": { "MultiplePeopleWithOneWord": {
Message: "this is a message for @user", Message: "this is a message for @user",
Keywords: map[string][]string{"@user": {id1, id2}}, Keywords: map[string][]string{"@user": {id1, id2}},
@@ -188,6 +198,18 @@ func TestGetExplicitMentions(t *testing.T) {
ChannelMentioned: true, ChannelMentioned: true,
}, },
}, },
"ChannelWithColonAtEnd": {
Message: "this is a message for @channel:",
Keywords: map[string][]string{"@channel": {id1, id2}},
Expected: &ExplicitMentions{
MentionedUserIds: map[string]bool{
id1: true,
id2: true,
},
ChannelMentioned: true,
},
},
"CapitalizedChannel": { "CapitalizedChannel": {
Message: "this is an message for @cHaNNeL", Message: "this is an message for @cHaNNeL",
Keywords: map[string][]string{"@channel": {id1, id2}}, Keywords: map[string][]string{"@channel": {id1, id2}},
@@ -210,6 +232,17 @@ func TestGetExplicitMentions(t *testing.T) {
AllMentioned: true, AllMentioned: true,
}, },
}, },
"AllWithColonAtEnd": {
Message: "this is a message for @all:",
Keywords: map[string][]string{"@all": {id1, id2}},
Expected: &ExplicitMentions{
MentionedUserIds: map[string]bool{
id1: true,
id2: true,
},
AllMentioned: true,
},
},
"CapitalizedAll": { "CapitalizedAll": {
Message: "this is an message for @ALL", Message: "this is an message for @ALL",
Keywords: map[string][]string{"@all": {id1, id2}}, Keywords: map[string][]string{"@all": {id1, id2}},
@@ -230,6 +263,15 @@ func TestGetExplicitMentions(t *testing.T) {
}, },
}, },
}, },
"AtUserWithColonAtEnd": {
Message: "this is a message for @user:",
Keywords: map[string][]string{"@user": {id1}},
Expected: &ExplicitMentions{
MentionedUserIds: map[string]bool{
id1: true,
},
},
},
"AtUserWithPeriodAtEndOfSentence": { "AtUserWithPeriodAtEndOfSentence": {
Message: "this is a message for @user.period.", Message: "this is a message for @user.period.",
Keywords: map[string][]string{"@user.period": {id1}}, Keywords: map[string][]string{"@user.period": {id1}},
@@ -248,6 +290,15 @@ func TestGetExplicitMentions(t *testing.T) {
}, },
}, },
}, },
"UserWithColonAtEnd": {
Message: "this is a message for user:",
Keywords: map[string][]string{"user": {id1}},
Expected: &ExplicitMentions{
MentionedUserIds: map[string]bool{
id1: true,
},
},
},
"PotentialOutOfChannelUser": { "PotentialOutOfChannelUser": {
Message: "this is an message for @potential and @user", Message: "this is an message for @potential and @user",
Keywords: map[string][]string{"@user": {id1}}, Keywords: map[string][]string{"@user": {id1}},
@@ -452,6 +503,7 @@ func TestGetExplicitMentionsAtHere(t *testing.T) {
"\\@here\\": true, "\\@here\\": true,
"|@here|": true, "|@here|": true,
";@here;": true, ";@here;": true,
"@here:": true,
":@here:": false, // This case shouldn't trigger a mention since it follows the format of reactions e.g. :word: ":@here:": false, // This case shouldn't trigger a mention since it follows the format of reactions e.g. :word:
"'@here'": true, "'@here'": true,
"\"@here\"": true, "\"@here\"": true,
@@ -991,7 +1043,7 @@ func TestGetDirectMessageNotificationEmailSubject(t *testing.T) {
th := Setup() th := Setup()
defer th.TearDown() defer th.TearDown()
expectedPrefix := "[http://localhost:8065] New Direct Message from sender on" expectedPrefix := "[http://localhost:8065] New Direct Message from @sender on"
post := &model.Post{ post := &model.Post{
CreateAt: 1501804801000, CreateAt: 1501804801000,
} }
@@ -1002,6 +1054,38 @@ func TestGetDirectMessageNotificationEmailSubject(t *testing.T) {
} }
} }
func TestGetGroupMessageNotificationEmailSubjectFull(t *testing.T) {
th := Setup()
defer th.TearDown()
expectedPrefix := "[http://localhost:8065] New Group Message in sender on"
post := &model.Post{
CreateAt: 1501804801000,
}
translateFunc := utils.GetUserTranslations("en")
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
subject := getGroupMessageNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "sender", emailNotificationContentsType)
if !strings.HasPrefix(subject, expectedPrefix) {
t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
}
}
func TestGetGroupMessageNotificationEmailSubjectGeneric(t *testing.T) {
th := Setup()
defer th.TearDown()
expectedPrefix := "[http://localhost:8065] New Group Message on"
post := &model.Post{
CreateAt: 1501804801000,
}
translateFunc := utils.GetUserTranslations("en")
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
subject := getGroupMessageNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "sender", emailNotificationContentsType)
if !strings.HasPrefix(subject, expectedPrefix) {
t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
}
}
func TestGetNotificationEmailSubject(t *testing.T) { func TestGetNotificationEmailSubject(t *testing.T) {
th := Setup() th := Setup()
defer th.TearDown() defer th.TearDown()
@@ -1029,21 +1113,22 @@ func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) {
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_OPEN, Type: model.CHANNEL_OPEN,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification.") { if !strings.Contains(body, "You have a new notification.") {
t.Fatal("Expected email text 'You have a new notification. Got " + body) t.Fatal("Expected email text 'You have a new notification. Got " + body)
} }
if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if !strings.Contains(body, "Channel: "+channel.DisplayName) {
t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Expected email text 'Channel: " + channel.DisplayName + "'. Got " + body)
} }
if !strings.Contains(body, senderName+" - ") { if !strings.Contains(body, "@"+senderName+" - ") {
t.Fatal("Expected email text '" + senderName + " - '. Got " + body) t.Fatal("Expected email text '@" + senderName + " - '. Got " + body)
} }
if !strings.Contains(body, post.Message) { if !strings.Contains(body, post.Message) {
t.Fatal("Expected email text '" + post.Message + "'. Got " + body) t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
@@ -1065,21 +1150,22 @@ func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_GROUP, Type: model.CHANNEL_GROUP,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification.") { if !strings.Contains(body, "You have a new Group Message.") {
t.Fatal("Expected email text 'You have a new notification. Got " + body) t.Fatal("Expected email text 'You have a new Group Message. Got " + body)
} }
if !strings.Contains(body, "CHANNEL: Group Message") { if !strings.Contains(body, "Channel: ChannelName") {
t.Fatal("Expected email text 'CHANNEL: Group Message'. Got " + body) t.Fatal("Expected email text 'Channel: ChannelName'. Got " + body)
} }
if !strings.Contains(body, senderName+" - ") { if !strings.Contains(body, "@"+senderName+" - ") {
t.Fatal("Expected email text '" + senderName + " - '. Got " + body) t.Fatal("Expected email text '@" + senderName + " - '. Got " + body)
} }
if !strings.Contains(body, post.Message) { if !strings.Contains(body, post.Message) {
t.Fatal("Expected email text '" + post.Message + "'. Got " + body) t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
@@ -1101,21 +1187,22 @@ func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_PRIVATE, Type: model.CHANNEL_PRIVATE,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification.") { if !strings.Contains(body, "You have a new notification.") {
t.Fatal("Expected email text 'You have a new notification. Got " + body) t.Fatal("Expected email text 'You have a new notification. Got " + body)
} }
if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if !strings.Contains(body, "Channel: "+channel.DisplayName) {
t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Expected email text 'Channel: " + channel.DisplayName + "'. Got " + body)
} }
if !strings.Contains(body, senderName+" - ") { if !strings.Contains(body, "@"+senderName+" - ") {
t.Fatal("Expected email text '" + senderName + " - '. Got " + body) t.Fatal("Expected email text '@" + senderName + " - '. Got " + body)
} }
if !strings.Contains(body, post.Message) { if !strings.Contains(body, post.Message) {
t.Fatal("Expected email text '" + post.Message + "'. Got " + body) t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
@@ -1137,18 +1224,19 @@ func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_DIRECT, Type: model.CHANNEL_DIRECT,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new direct message.") { if !strings.Contains(body, "You have a new Direct Message.") {
t.Fatal("Expected email text 'You have a new direct message. Got " + body) t.Fatal("Expected email text 'You have a new Direct Message. Got " + body)
} }
if !strings.Contains(body, senderName+" - ") { if !strings.Contains(body, "@"+senderName+" - ") {
t.Fatal("Expected email text '" + senderName + " - '. Got " + body) t.Fatal("Expected email text '@" + senderName + " - '. Got " + body)
} }
if !strings.Contains(body, post.Message) { if !strings.Contains(body, post.Message) {
t.Fatal("Expected email text '" + post.Message + "'. Got " + body) t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
@@ -1171,18 +1259,19 @@ func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T)
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_OPEN, Type: model.CHANNEL_OPEN,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification from "+senderName) { if !strings.Contains(body, "You have a new notification from @"+senderName) {
t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body) t.Fatal("Expected email text 'You have a new notification from @" + senderName + "'. Got " + body)
} }
if strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if strings.Contains(body, "Channel: "+channel.DisplayName) {
t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Did not expect email text 'Channel: " + channel.DisplayName + "'. Got " + body)
} }
if strings.Contains(body, post.Message) { if strings.Contains(body, post.Message) {
t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body) t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
@@ -1204,15 +1293,16 @@ func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_GROUP, Type: model.CHANNEL_GROUP,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification from "+senderName) { if !strings.Contains(body, "You have a new Group Message from @"+senderName) {
t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body) t.Fatal("Expected email text 'You have a new Group Message from @" + senderName + "'. Got " + body)
} }
if strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
@@ -1237,15 +1327,16 @@ func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T)
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_PRIVATE, Type: model.CHANNEL_PRIVATE,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new notification from "+senderName) { if !strings.Contains(body, "You have a new notification from @"+senderName) {
t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body) t.Fatal("Expected email text 'You have a new notification from @" + senderName + "'. Got " + body)
} }
if strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
@@ -1270,15 +1361,16 @@ func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T)
DisplayName: "ChannelName", DisplayName: "ChannelName",
Type: model.CHANNEL_DIRECT, Type: model.CHANNEL_DIRECT,
} }
channelName := "ChannelName"
senderName := "sender" senderName := "sender"
teamName := "team" teamName := "team"
teamURL := "http://localhost:8065/" + teamName teamURL := "http://localhost:8065/" + teamName
emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
translateFunc := utils.GetUserTranslations("en") translateFunc := utils.GetUserTranslations("en")
body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc) body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
if !strings.Contains(body, "You have a new direct message from "+senderName) { if !strings.Contains(body, "You have a new Direct Message from @"+senderName) {
t.Fatal("Expected email text 'You have a new direct message from " + senderName + "'. Got " + body) t.Fatal("Expected email text 'You have a new Direct Message from @" + senderName + "'. Got " + body)
} }
if strings.Contains(body, "CHANNEL: "+channel.DisplayName) { if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body) t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)

Просмотреть файл

@@ -661,3 +661,7 @@ func (a *App) ExecutePluginCommand(args *model.CommandArgs) (*model.Command, *mo
} }
return nil, nil, nil return nil, nil, nil
} }
func (a *App) PluginsReady() bool {
return a.PluginEnv != nil && *a.Config().PluginSettings.Enable
}

Просмотреть файл

@@ -160,6 +160,14 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
return nil, err return nil, err
} }
if a.PluginsReady() {
if newPost, rejectionReason := a.PluginEnv.Hooks().MessageWillBePosted(post); newPost == nil {
return nil, model.NewAppError("createPost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
} else {
post = newPost
}
}
var rpost *model.Post var rpost *model.Post
if result := <-a.Srv.Store.Post().Save(post); result.Err != nil { if result := <-a.Srv.Store.Post().Save(post); result.Err != nil {
return nil, result.Err return nil, result.Err
@@ -167,6 +175,12 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
rpost = result.Data.(*model.Post) rpost = result.Data.(*model.Post)
} }
if a.PluginsReady() {
a.Go(func() {
a.PluginEnv.Hooks().MessageHasBeenPosted(rpost)
})
}
esInterface := a.Elasticsearch esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing { if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Go(func() { a.Go(func() {
@@ -371,11 +385,25 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model
return nil, err return nil, err
} }
if a.PluginsReady() {
if pluginModifiedPost, rejectionReason := a.PluginEnv.Hooks().MessageWillBeUpdated(newPost, oldPost); pluginModifiedPost == nil {
return nil, model.NewAppError("createPost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
} else {
newPost = pluginModifiedPost
}
}
if result := <-a.Srv.Store.Post().Update(newPost, oldPost); result.Err != nil { if result := <-a.Srv.Store.Post().Update(newPost, oldPost); result.Err != nil {
return nil, result.Err return nil, result.Err
} else { } else {
rpost := result.Data.(*model.Post) rpost := result.Data.(*model.Post)
if a.PluginsReady() {
a.Go(func() {
a.PluginEnv.Hooks().MessageHasBeenUpdated(newPost, oldPost)
})
}
esInterface := a.Elasticsearch esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing { if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Go(func() { a.Go(func() {

Просмотреть файл

@@ -177,8 +177,9 @@ func (a *App) Publish(message *model.WebSocketEvent) {
func (a *App) PublishSkipClusterSend(message *model.WebSocketEvent) { func (a *App) PublishSkipClusterSend(message *model.WebSocketEvent) {
if message.Broadcast.UserId != "" { if message.Broadcast.UserId != "" {
if len(a.Hubs) != 0 { hub := a.GetHubForUserId(message.Broadcast.UserId)
a.GetHubForUserId(message.Broadcast.UserId).Broadcast(message) if hub != nil {
hub.Broadcast(message)
} }
} else { } else {
for _, hub := range a.Hubs { for _, hub := range a.Hubs {
@@ -299,8 +300,9 @@ func (a *App) InvalidateCacheForUserSkipClusterSend(userId string) {
a.Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId) a.Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId)
a.Srv.Store.User().InvalidatProfileCacheForUser(userId) a.Srv.Store.User().InvalidatProfileCacheForUser(userId)
if len(a.Hubs) != 0 { hub := a.GetHubForUserId(userId)
a.GetHubForUserId(userId).InvalidateUser(userId) if hub != nil {
hub.InvalidateUser(userId)
} }
} }
@@ -322,8 +324,9 @@ func (a *App) InvalidateCacheForWebhookSkipClusterSend(webhookId string) {
} }
func (a *App) InvalidateWebConnSessionCacheForUser(userId string) { func (a *App) InvalidateWebConnSessionCacheForUser(userId string) {
if len(a.Hubs) != 0 { hub := a.GetHubForUserId(userId)
a.GetHubForUserId(userId).InvalidateUser(userId) if hub != nil {
hub.InvalidateUser(userId)
} }
} }

Просмотреть файл

@@ -422,6 +422,10 @@ func updateUserEmailCmdF(command *cobra.Command, args []string) error {
} }
defer a.Shutdown() defer a.Shutdown()
if len(args) != 2 {
return errors.New("Expected two arguments. See help text for details.")
}
newEmail := args[1] newEmail := args[1]
if !model.IsValidEmail(newEmail) { if !model.IsValidEmail(newEmail) {
@@ -440,7 +444,7 @@ func updateUserEmailCmdF(command *cobra.Command, args []string) error {
user.Email = newEmail user.Email = newEmail
_, errUpdate := a.UpdateUser(user, true) _, errUpdate := a.UpdateUser(user, true)
if errUpdate != nil { if errUpdate != nil {
return errUpdate return errors.New(errUpdate.Message)
} }
return nil return nil

Просмотреть файл

@@ -104,7 +104,19 @@ func TestChangeUserEmail(t *testing.T) {
// should fail because using an invalid email // should fail because using an invalid email
require.Error(t, cmd.RunCommand(t, "user", "email", th.BasicUser.Username, "wrong$email.com")) require.Error(t, cmd.RunCommand(t, "user", "email", th.BasicUser.Username, "wrong$email.com"))
// should fail because missing one parameter
require.Error(t, cmd.RunCommand(t, "user", "email", th.BasicUser.Username))
// should fail because missing both parameters
require.Error(t, cmd.RunCommand(t, "user", "email"))
// should fail because have more than 2 parameters
require.Error(t, cmd.RunCommand(t, "user", "email", th.BasicUser.Username, "new@email.com", "extra!"))
// should fail because user not found // should fail because user not found
require.Error(t, cmd.RunCommand(t, "user", "email", "invalidUser", newEmail)) require.Error(t, cmd.RunCommand(t, "user", "email", "invalidUser", newEmail))
// should fail because email already in use
require.Error(t, cmd.RunCommand(t, "user", "email", th.BasicUser.Username, th.BasicUser2.Email))
} }

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "Dieser Standard-Kanal kann nicht in einen privaten Kanal umgewandelt werden."
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "Der umzuwandelnde Kanal ist bereits ein privater Kanal."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -792,11 +792,11 @@
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "Benutzer in einen Kanal einladen"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
"translation": "Sie können keinen Benutzer aus einem Direktnachrichtenkanal entfernen." "translation": "Sie können keinen Benutzer einem Direktnachrichtenkanal hinzufügen."
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
@@ -804,11 +804,11 @@
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
"translation": "@[username] ~[channel]" "translation": "@[Benutzername] ~[Kanal]"
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "Benutzername und Kanal fehlen."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
@@ -816,19 +816,19 @@
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "einladen"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "Sie haben nicht die nötigen Berechtigungen um {{.User}} dem Kanal {{.Channel}} hinzuzufügen."
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.User}} wurde dem Kanal {{.Channel}} hinzugefügt."
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "{{.User}} ist bereits im Kanal."
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -960,11 +960,11 @@
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "Konnte den Kanal {{.Channel}} nicht finden. Bitte nutzen Sie den [Kanal-Handle](https://about.mattermost.com/default-channel-handle-documentation), um Kanäle zu identifizieren." "translation": "Konnte den Kanal nicht finden. Bitte nutzen Sie den [Kanal-Handle](https://about.mattermost.com/default-channel-handle-documentation), um Kanäle zu identifizieren."
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "Kanal {{.Channel}} konnte nicht stumm geschaltet werden, da Sie kein Mitglied sind."
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Ein Fehler ist beim Aufrufen des Teams aufgetreten"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Ein Fehler ist beim Aktualisieren des Teamsymbols aufgetreten"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2860,7 +2860,7 @@
}, },
{ {
"id": "api.user.create_user.missing_token.app_error", "id": "api.user.create_user.missing_token.app_error",
"translation": "Missing Token." "translation": "Fehlendes Token."
}, },
{ {
"id": "api.user.create_user.no_open_server", "id": "api.user.create_user.no_open_server",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "Profilbild konnte nicht abgerufen werden, Benutzer nicht gefunden."
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "Verbindung nicht erfolgreich: {{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Kann extrahiertes Plugin nicht aktivieren. Plugin könnte schon existieren und aktiviert sein." "translation": "Extrahiertes Plugin konnte nicht aktiviert werden."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Konnte aktive Plugins nicht ermitteln" "translation": "Konnte aktive Plugins nicht ermitteln"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Plugin-ID muss kürzer als {{.Max}} Zeichen sein."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Konnte Plugin nicht installieren." "translation": "Konnte Plugin nicht installieren."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Konnte Plugin nicht installieren. Ein Plugin mit der selben ID ist bereits installiert." "translation": "Konnte Plugin nicht installieren. Ein Plugin mit der selben ID ist bereits installiert."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin-Id muss aus mindestens {{.Min}} und maximal {{.Max}} Zeichen bestehen und zu {{.Regex}} passen."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Konnte Manifest des extrahierten Plugins nicht abrufen" "translation": "Konnte Manifest des extrahierten Plugins nicht abrufen"
@@ -6576,7 +6576,7 @@
}, },
{ {
"id": "store.sql_preference.cleanup_flags_batch.app_error", "id": "store.sql_preference.cleanup_flags_batch.app_error",
"translation": "Es ist ein Fehler beim permanenten Löschen des Stapels von Flags aufgetreten" "translation": "Es ist ein Fehler beim permanenten Löschen des Stapels von Markierungen aufgetreten"
}, },
{ {
"id": "store.sql_preference.delete.app_error", "id": "store.sql_preference.delete.app_error",
@@ -6692,7 +6692,7 @@
}, },
{ {
"id": "store.sql_role.permanent_delete_all.app_error", "id": "store.sql_role.permanent_delete_all.app_error",
"translation": "We could not permanently delete all the roles" "translation": "Es konnten nicht alle Rollen permanent gelöscht werden"
}, },
{ {
"id": "store.sql_role.save.insert.app_error", "id": "store.sql_role.save.insert.app_error",
@@ -6812,7 +6812,7 @@
}, },
{ {
"id": "store.sql_system.permanent_delete_by_name.app_error", "id": "store.sql_system.permanent_delete_by_name.app_error",
"translation": "We could not permanently delete the system table entry" "translation": "System-Tabelleneintrag konnte nicht permanent gelöscht werden"
}, },
{ {
"id": "store.sql_system.save.app_error", "id": "store.sql_system.save.app_error",
@@ -7384,7 +7384,7 @@
}, },
{ {
"id": "utils.mail.send_mail.from_address.app_error", "id": "utils.mail.send_mail.from_address.app_error",
"translation": "Error setting \"From Address\"" "translation": "Fehler beim Setzen von \"Absenderadresse\""
}, },
{ {
"id": "utils.mail.send_mail.msg.app_error", "id": "utils.mail.send_mail.msg.app_error",
@@ -7400,7 +7400,7 @@
}, },
{ {
"id": "utils.mail.send_mail.to_address.app_error", "id": "utils.mail.send_mail.to_address.app_error",
"translation": "Error setting \"To Address\"" "translation": "Fehler beim Setzen von \"Empfängeradresse\""
}, },
{ {
"id": "utils.mail.test.configured.error", "id": "utils.mail.test.configured.error",

Просмотреть файл

@@ -870,6 +870,10 @@
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}."
}, },
{
"id": "api.command_invite.private_channel.app_error",
"translation": "Could not find the channel {{.Channel}}. Please use the channel handle to identify channels."
},
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.User}} added to {{.Channel}} channel."
@@ -3828,11 +3832,11 @@
}, },
{ {
"id": "app.notification.body.intro.direct.full", "id": "app.notification.body.intro.direct.full",
"translation": "You have a new direct message." "translation": "You have a new Direct Message."
}, },
{ {
"id": "app.notification.body.intro.direct.generic", "id": "app.notification.body.intro.direct.generic",
"translation": "You have a new direct message from {{.SenderName}}" "translation": "You have a new Direct Message from @{{.SenderName}}"
}, },
{ {
"id": "app.notification.body.intro.notification.full", "id": "app.notification.body.intro.notification.full",
@@ -3840,11 +3844,19 @@
}, },
{ {
"id": "app.notification.body.intro.notification.generic", "id": "app.notification.body.intro.notification.generic",
"translation": "You have a new notification from {{.SenderName}}" "translation": "You have a new notification from @{{.SenderName}}"
},
{
"id": "app.notification.body.intro.group_message.full",
"translation": "You have a new Group Message."
},
{
"id": "app.notification.body.intro.group_message.generic",
"translation": "You have a new Group Message from @{{.SenderName}}"
}, },
{ {
"id": "app.notification.body.text.direct.full", "id": "app.notification.body.text.direct.full",
"translation": "{{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}" "translation": "@{{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}"
}, },
{ {
"id": "app.notification.body.text.direct.generic", "id": "app.notification.body.text.direct.generic",
@@ -3852,20 +3864,36 @@
}, },
{ {
"id": "app.notification.body.text.notification.full", "id": "app.notification.body.text.notification.full",
"translation": "CHANNEL: {{.ChannelName}}<br>{{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}" "translation": "Channel: {{.ChannelName}}<br>@{{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}"
}, },
{ {
"id": "app.notification.body.text.notification.generic", "id": "app.notification.body.text.notification.generic",
"translation": "{{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}" "translation": "{{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}"
}, },
{
"id": "app.notification.body.text.group_message.full",
"translation": "Channel: {{.ChannelName}}<br>@{{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}"
},
{
"id": "app.notification.body.text.group_message.generic",
"translation": "{{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}"
},
{ {
"id": "app.notification.subject.direct.full", "id": "app.notification.subject.direct.full",
"translation": "[{{.SiteName}}] New Direct Message from {{.SenderDisplayName}} on {{.Month}} {{.Day}}, {{.Year}}" "translation": "[{{.SiteName}}] New Direct Message from @{{.SenderDisplayName}} on {{.Month}} {{.Day}}, {{.Year}}"
}, },
{ {
"id": "app.notification.subject.notification.full", "id": "app.notification.subject.notification.full",
"translation": "[{{ .SiteName }}] Notification in {{ .TeamName}} on {{.Month}} {{.Day}}, {{.Year}}" "translation": "[{{ .SiteName }}] Notification in {{ .TeamName}} on {{.Month}} {{.Day}}, {{.Year}}"
}, },
{
"id": "app.notification.subject.group_message.full",
"translation": "[{{ .SiteName }}] New Group Message in {{ .ChannelName}} on {{.Month}} {{.Day}}, {{.Year}}"
},
{
"id": "app.notification.subject.group_message.generic",
"translation": "[{{ .SiteName }}] New Group Message on {{.Month}} {{.Day}}, {{.Year}}"
},
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin." "translation": "Unable to activate extracted plugin."
@@ -3902,10 +3930,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Unable to get active plugins" "translation": "Unable to get active plugins"
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Unable to install plugin." "translation": "Unable to install plugin."
@@ -3914,6 +3938,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Unable to install plugin. A plugin with the same ID is already installed." "translation": "Unable to install plugin. A plugin with the same ID is already installed."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Unable to find manifest for extracted plugin" "translation": "Unable to find manifest for extracted plugin"

Просмотреть файл

@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Ocurrió un error al obtener el equipo"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Ocurrió un error al actualizar el icono del equipo"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "No se puede activar el plugin extraído. Puede que el plugin ya exista y esté activo." "translation": "No se puede activar el complemento extraído."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "No se puede obtener los complementos activos" "translation": "No se puede obtener los complementos activos"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Id del Plugin debe tener menos de {{.Max}} caracteres."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "No se puede instalar el plugin." "translation": "No se puede instalar el plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "No se puede instalar el plugin. Un plugin con el mismo ID ya está instalado." "translation": "No se puede instalar el plugin. Un plugin con el mismo ID ya está instalado."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "El Id del complemento debe tener al menos {{.Min}} caracteres y un máximo de {{.Max}} caracteres que coincidan con {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "No se puede encontrar el manifiesto del plugin extraído" "translation": "No se puede encontrar el manifiesto del plugin extraído"

Просмотреть файл

@@ -109,15 +109,15 @@
}, },
{ {
"id": "api.admin.test_s3.missing_s3_bucket", "id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required" "translation": "Un Bucket S3 est requis"
}, },
{ {
"id": "api.admin.test_s3.missing_s3_endpoint", "id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required" "translation": "Un noeud (endpoint) S3 est requis"
}, },
{ {
"id": "api.admin.test_s3.missing_s3_region", "id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required" "translation": "Une région S3 est requise"
}, },
{ {
"id": "api.admin.upload_brand_image.array.app_error", "id": "api.admin.upload_brand_image.array.app_error",
@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "Le canal par défaut ne peut pas être converti en un canal privé."
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "Le canal que vous essayez de convertir est déjà un canal privé."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -788,15 +788,15 @@
}, },
{ {
"id": "api.command_invite.channel.error", "id": "api.command_invite.channel.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Impossible de trouver le canal {{.Channel}}. Veuillez utiliser l'[identifiant de canal](https://about.mattermost.com/default-channel-handle-documentation) pour identifier les canaux."
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "Inviter un utilisateur à rejoindre un canal"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
"translation": "Vous ne pouvez pas retirer un utilisateur d'un canal de messages personnels." "translation": "Vous ne pouvez pas ajouter un utilisateur dans un canal de messages personnels."
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
@@ -804,31 +804,31 @@
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
"translation": "@[username] ~[channel]" "translation": "@[nom d'utilisateur] ~[canal]"
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "Nom d'utilisateur et canal manquants."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
"translation": "Utilisateur introuvable" "translation": "Utilisateur introuvable."
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "Inviter"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "Vous n'avez pas les permissions nécessaires pour ajouter {{.User}} dans {{.Channel}}."
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.User}} a été ajouté dans {{.Channel}}."
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "{{.User}} est déjà membre de ce canal."
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -840,7 +840,7 @@
}, },
{ {
"id": "api.command_join.hint", "id": "api.command_join.hint",
"translation": "~[channel]" "translation": "~[canal]"
}, },
{ {
"id": "api.command_join.list.app_error", "id": "api.command_join.list.app_error",
@@ -944,43 +944,43 @@
}, },
{ {
"id": "api.command_mute.desc", "id": "api.command_mute.desc",
"translation": "Turns off desktop, email and push notifications for the current channel or the [channel] specified." "translation": "Désactive les notifications de bureau, par e-mail et push pour le canal actuel ou pour le canal [channel]."
}, },
{ {
"id": "api.command_mute.error", "id": "api.command_mute.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Impossible de trouver le canal {{.Channel}}. Veuillez utiliser l'[identifiant de canal](https://about.mattermost.com/default-channel-handle-documentation) pour identifier les canaux."
}, },
{ {
"id": "api.command_mute.hint", "id": "api.command_mute.hint",
"translation": "~[channel]" "translation": "~[canal]"
}, },
{ {
"id": "api.command_mute.name", "id": "api.command_mute.name",
"translation": "mute" "translation": "sourdine"
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "Could not find the specified channel. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Impossible de trouver le canal spécifié. Veuillez utiliser l'[identifiant de canal](https://about.mattermost.com/default-channel-handle-documentation) pour identifier les canaux."
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "Impossible de mettre en sourdine le canal {{.Channel}}, car vous n'êtes pas membre de celui-ci."
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
"translation": "You will not receive notifications for {{.Channel}} until channel mute is turned off." "translation": "Vous ne recevrez pas de notifications pour le canal {{.Channel}} jusqu'à ce que vous désactiviez le mode sourdine."
}, },
{ {
"id": "api.command_mute.success_mute_direct_msg", "id": "api.command_mute.success_mute_direct_msg",
"translation": "You will not receive notifications for this channel until channel mute is turned off." "translation": "Vous ne recevrez pas de notifications pour ce canal jusqu'à ce que vous désactiviez le mode sourdine."
}, },
{ {
"id": "api.command_mute.success_unmute", "id": "api.command_mute.success_unmute",
"translation": "{{.Channel}} is no longer muted." "translation": "{{.Channel}} n'est plus en sourdine."
}, },
{ {
"id": "api.command_mute.success_unmute_direct_msg", "id": "api.command_mute.success_unmute_direct_msg",
"translation": "This channel is no longer muted." "translation": "Ce canal n'est plus en sourdine."
}, },
{ {
"id": "api.command_offline.desc", "id": "api.command_offline.desc",
@@ -1478,7 +1478,7 @@
}, },
{ {
"id": "api.file.upload_file.incorrect_number_of_files.app_error", "id": "api.file.upload_file.incorrect_number_of_files.app_error",
"translation": "Unable to upload files. Incorrect number of files specified." "translation": "Impossible d'envoyer des fichiers. Le nombre de fichiers spécifié est incorrect."
}, },
{ {
"id": "api.file.upload_file.large_image.app_error", "id": "api.file.upload_file.large_image.app_error",
@@ -1750,11 +1750,11 @@
}, },
{ {
"id": "api.post.check_for_out_of_channel_mentions.message.multiple", "id": "api.post.check_for_out_of_channel_mentions.message.multiple",
"translation": "{{.Usernames}} et {{.LastUsername}} ont été mentionnés, mais, ne faisant pas partie de ce canal, ils ne recevront pas de notifications." "translation": "@{{.Usernames}} et @{{.LastUsername}} ont été mentionnés, mais, ne faisant pas partie de ce canal, ils ne recevront pas de notifications."
}, },
{ {
"id": "api.post.check_for_out_of_channel_mentions.message.one", "id": "api.post.check_for_out_of_channel_mentions.message.one",
"translation": "{{.Username}} a été mentionné(e), mais, ne faisant pas partie de ce canal, ne recevra pas de notification." "translation": "@{{.Username}} a été mentionné(e), mais, ne faisant pas partie de ce canal, il/elle ne recevra pas de notification."
}, },
{ {
"id": "api.post.create_post.attach_files.error", "id": "api.post.create_post.attach_files.error",
@@ -1920,7 +1920,7 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only_no_channel", "id": "api.post.send_notifications_and_forget.push_image_only_no_channel",
"translation": " a envoyé un ou plusieurs fichiers dans " "translation": " a envoyé un ou plusieurs fichiers"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_in", "id": "api.post.send_notifications_and_forget.push_in",
@@ -2036,7 +2036,7 @@
}, },
{ {
"id": "api.roles.patch_roles.license.error", "id": "api.roles.patch_roles.license.error",
"translation": "Your current license does not support advanced permissions." "translation": "Votre licence actuelle ne supporte pas les permissions avancées."
}, },
{ {
"id": "api.saml.save_certificate.app_error", "id": "api.saml.save_certificate.app_error",
@@ -2048,11 +2048,11 @@
}, },
{ {
"id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt", "id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt",
"translation": "Must enable Forward80To443 when using LetsEncrypt" "translation": "Vous devez activer l'option Forward80To443 pour pouvoir utiliser LetsEncrypt"
}, },
{ {
"id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port", "id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port",
"translation": "Cannot forward port 80 to port 443 while listening on port %s: disable Forward80To443 if using a proxy server" "translation": "Impossible de rediriger le port 80 sur le port 443 alors que le serveur écoute sur le port %s : désactivez l'option Forward80To443 si vous utilisez un serveur de proxy"
}, },
{ {
"id": "api.server.start_server.listening.info", "id": "api.server.start_server.listening.info",
@@ -2420,11 +2420,11 @@
}, },
{ {
"id": "api.team.move_channel.post.error", "id": "api.team.move_channel.post.error",
"translation": "Impossible de publier la description du canal" "translation": "Impossible de publier le message indiquant que le canal a été déplacé."
}, },
{ {
"id": "api.team.move_channel.success", "id": "api.team.move_channel.success",
"translation": "This channel has been moved to this team from %v." "translation": "Ce canal a été déplacé vers cette équipe par %v."
}, },
{ {
"id": "api.team.permanent_delete_team.attempting.warn", "id": "api.team.permanent_delete_team.attempting.warn",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Une erreur s'est produite lors de la récupération de l'équipe"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2448,27 +2448,27 @@
}, },
{ {
"id": "api.team.set_team_icon.array.app_error", "id": "api.team.set_team_icon.array.app_error",
"translation": "Aucune image transmise dans la requête" "translation": "Tableau vide dans le paramètre 'image' de la requête"
}, },
{ {
"id": "api.team.set_team_icon.decode.app_error", "id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon" "translation": "Impossible de décoder l'icône d'équipe."
}, },
{ {
"id": "api.team.set_team_icon.decode_config.app_error", "id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata" "translation": "Impossible de décoder les métadonnées de l'icône d'équipe"
}, },
{ {
"id": "api.team.set_team_icon.encode.app_error", "id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon" "translation": "Impossible d'encoder l'icône d'équipe"
}, },
{ {
"id": "api.team.set_team_icon.get_team.app_error", "id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Une erreur s'est produite lors de la récupération de l'équipe"
}, },
{ {
"id": "api.team.set_team_icon.no_file.app_error", "id": "api.team.set_team_icon.no_file.app_error",
"translation": "Pas de fichier dans le paramètre \"image\" de la requête" "translation": "Pas de fichier dans le paramètre 'image' de la requête"
}, },
{ {
"id": "api.team.set_team_icon.open.app_error", "id": "api.team.set_team_icon.open.app_error",
@@ -2480,15 +2480,15 @@
}, },
{ {
"id": "api.team.set_team_icon.storage.app_error", "id": "api.team.set_team_icon.storage.app_error",
"translation": "Impossible d'envoyer le fichier. Le stockage d'images n'est pas configuré." "translation": "Impossible d'envoyer l'icône d'équipe. Le stockage d'images n'est pas configuré."
}, },
{ {
"id": "api.team.set_team_icon.too_large.app_error", "id": "api.team.set_team_icon.too_large.app_error",
"translation": "Impossible d'envoyer le fichier. Le fichier est trop volumineux." "translation": "Impossible d'envoyer l'icône d'équipe. Le fichier est trop volumineux."
}, },
{ {
"id": "api.team.set_team_icon.write_file.app_error", "id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon" "translation": "Impossible d'enregistrer l'icône d'équipe"
}, },
{ {
"id": "api.team.signup_team.email_disabled.app_error", "id": "api.team.signup_team.email_disabled.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Une erreur est survenue lors du changement d'icône d'équipe."
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2860,7 +2860,7 @@
}, },
{ {
"id": "api.user.create_user.missing_token.app_error", "id": "api.user.create_user.missing_token.app_error",
"translation": "Missing Token." "translation": "Jeton manquant."
}, },
{ {
"id": "api.user.create_user.no_open_server", "id": "api.user.create_user.no_open_server",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "Impossible de récupérer l'image de profil, utilisateur introuvable."
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3244,7 +3244,7 @@
}, },
{ {
"id": "api.webhook.incoming.error", "id": "api.webhook.incoming.error",
"translation": "Could not decode the multipart payload of incoming webhook." "translation": "Impossible de décoder la charge utile multipart du webhook entrant."
}, },
{ {
"id": "api.webhook.init.debug", "id": "api.webhook.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "La connexion n'a pas pu être établie : {{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3812,11 +3812,11 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Impossible d'activer le plugin extrait. Il se peut qu'il existe déjà et soit déjà activé." "translation": "Impossible d'activer le plugin extrait."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled." "translation": "La configuration du plugin dans votre fichier config.json doit être mise à jour manuellement lorsque vous utilisez l'option ReadOnlyConfig alors que le clustering est activé."
}, },
{ {
"id": "app.plugin.config.app_error", "id": "app.plugin.config.app_error",
@@ -3828,7 +3828,7 @@
}, },
{ {
"id": "app.plugin.disabled.app_error", "id": "app.plugin.disabled.app_error",
"translation": "Plugins have been disabled. Please check your logs for details." "translation": "Les plugins ont été désactivés. Veuillez consulter vos journaux (logs) pour plus d'information."
}, },
{ {
"id": "app.plugin.extract.app_error", "id": "app.plugin.extract.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Impossible de récupérer les plugins actifs" "translation": "Impossible de récupérer les plugins actifs"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "L'Id de plugin doit faire moins de {{.Max}} caractères."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Impossible d'installer le plugin." "translation": "Impossible d'installer le plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Impossible d'installer le plugin. Un plugin avec le même ID est déjà installé." "translation": "Impossible d'installer le plugin. Un plugin avec le même ID est déjà installé."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "L'identifiant du plugin doit contenir au moins {{.Min}} caractères, au plus {{.Max}} caractères et correspondre à la {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Impossible de trouver le manifeste pour le plugin extrait" "translation": "Impossible de trouver le manifeste pour le plugin extrait"
@@ -3880,7 +3880,7 @@
}, },
{ {
"id": "app.role.check_roles_exist.role_not_found", "id": "app.role.check_roles_exist.role_not_found",
"translation": "The provided role does not exist" "translation": "Le rôle spécifié n'existe pas"
}, },
{ {
"id": "app.team.join_user_to_team.max_accounts.app_error", "id": "app.team.join_user_to_team.max_accounts.app_error",
@@ -3888,15 +3888,15 @@
}, },
{ {
"id": "app.timezones.failed_deserialize.app_error", "id": "app.timezones.failed_deserialize.app_error",
"translation": "Failed to deserialize Timezone config file={{.Filename}}, err={{.Error}}" "translation": "Impossible de désérialiser le fichier de configuration du fuseau horaire={{.Filename}}, err={{.Error}}"
}, },
{ {
"id": "app.timezones.load_config.app_error", "id": "app.timezones.load_config.app_error",
"translation": "Timezone config file does not exists file={{.Filename}}" "translation": "Le fichier de configuration du fuseau horaire n'existe pas {{.Filename}}"
}, },
{ {
"id": "app.timezones.read_config.app_error", "id": "app.timezones.read_config.app_error",
"translation": "Failed to read Timezone config file={{.Filename}}, err={{.Error}}" "translation": "Impossible de lire le ficher de configuration du fuseau horaire={{.Filename}}, err={{.Error}}"
}, },
{ {
"id": "app.user_access_token.disabled", "id": "app.user_access_token.disabled",
@@ -4120,11 +4120,11 @@
}, },
{ {
"id": "ent.compliance.run_limit.warning", "id": "ent.compliance.run_limit.warning",
"translation": "Compliance export warning for job '{{.JobName}}' too many rows returned truncating to 30,000 at '{{.FilePath}}'" "translation": "Avertissement de conformité d'exportation pour le job '{{.JobName}}' : trop de lignes retournées, tronqué à 30 000 pour '{{.FilePath}}'"
}, },
{ {
"id": "ent.compliance.run_started.info", "id": "ent.compliance.run_started.info",
"translation": "L'export de compatibilité a démarré pour le job '{{.JobName}}' à '{{.FilePath}}'" "translation": "La conformité d'exportation a démarré pour le job '{{.JobName}}' à '{{.FilePath}}'"
}, },
{ {
"id": "ent.data_retention.generic.license.error", "id": "ent.data_retention.generic.license.error",
@@ -4380,15 +4380,15 @@
}, },
{ {
"id": "ent.migration.migratetosaml.email_already_used_by_other_user", "id": "ent.migration.migratetosaml.email_already_used_by_other_user",
"translation": "Email already used by another SAML user." "translation": "L'adresse e-mail est déja utilisée par un autre utilisateur SAML."
}, },
{ {
"id": "ent.migration.migratetosaml.user_not_found_in_users_mapping_file", "id": "ent.migration.migratetosaml.user_not_found_in_users_mapping_file",
"translation": "User not found in the users file." "translation": "Utilisateur introuvable dans le fichier utilisateurs."
}, },
{ {
"id": "ent.migration.migratetosaml.username_already_used_by_other_user", "id": "ent.migration.migratetosaml.username_already_used_by_other_user",
"translation": "Username already used by another Mattermost user." "translation": "Nom d'utilisateur déjà utilisé par un autre utilisateur de Mattermost."
}, },
{ {
"id": "ent.saml.attribute.app_error", "id": "ent.saml.attribute.app_error",
@@ -4656,7 +4656,7 @@
}, },
{ {
"id": "model.channel_member.is_valid.mute_value.app_error", "id": "model.channel_member.is_valid.mute_value.app_error",
"translation": "Invalid muting value" "translation": "Valeur de sourdine invalide"
}, },
{ {
"id": "model.channel_member.is_valid.notify_level.app_error", "id": "model.channel_member.is_valid.notify_level.app_error",
@@ -4672,7 +4672,7 @@
}, },
{ {
"id": "model.channel_member.is_valid.unread_level.app_error", "id": "model.channel_member.is_valid.unread_level.app_error",
"translation": "Niveau pour marquer comme non-lu invalide" "translation": "Niveau pour marquer comme non lu invalide"
}, },
{ {
"id": "model.channel_member.is_valid.user_id.app_error", "id": "model.channel_member.is_valid.user_id.app_error",
@@ -5100,11 +5100,11 @@
}, },
{ {
"id": "model.config.is_valid.message_export.export_type.app_error", "id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'" "translation": "Le paramètre ExportFormat de la tâche d'exportation de messages doit être « actiance » ou « globalrelay »"
}, },
{ {
"id": "model.config.is_valid.message_export.export_type.app_error", "id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'" "translation": "Le paramètre ExportFormat de la tâche d'exportation de messages doit être « actiance » ou « globalrelay »"
}, },
{ {
"id": "model.config.is_valid.message_export.file_location.app_error", "id": "model.config.is_valid.message_export.file_location.app_error",
@@ -5116,27 +5116,27 @@
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error", "id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing" "translation": "Le paramètre ExportFormat de la tâche d'exportation de messages est définie sur « globalrelay », mais le paramètre GlobalRelaySettings est manquant"
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error", "id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'" "translation": "Le paramètre GlobalRelaySettings.CustomerType de la tâche d'exportation de messages doit être « A9 » ou « A10 »"
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error", "id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address" "translation": "Le paramètre GlobalRelaySettings.EmailAddress de la tâche d'exportation de messages doit être une adresse e-mail valide"
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error", "id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set" "translation": "Le paramètre GlobalRelaySettings.SmtpPassword de la tâche d'exportation de messages doit être défini"
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error", "id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set" "translation": "Le paramètre GlobalRelaySettings.SmtpUsername de la tâche d'exportation de messages doit être défini"
}, },
{ {
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error", "id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address" "translation": "Le paramètre GlobalRelayEmailAddress de la tâche d'exportation de messages doit être une adresse e-mail valide"
}, },
{ {
"id": "model.config.is_valid.password_length.app_error", "id": "model.config.is_valid.password_length.app_error",
@@ -5268,7 +5268,7 @@
}, },
{ {
"id": "model.config.is_valid.websocket_url.app_error", "id": "model.config.is_valid.websocket_url.app_error",
"translation": "URL de site invalide. Il doit s'agir d'une URL valide et commencer par http:// ou https://." "translation": "L'URL websocket doit être une URL valide et commencer par ws:// ou wss://."
}, },
{ {
"id": "model.config.is_valid.write_timeout.app_error", "id": "model.config.is_valid.write_timeout.app_error",
@@ -6124,11 +6124,11 @@
}, },
{ {
"id": "store.sql_channel.update.exists.app_error", "id": "store.sql_channel.update.exists.app_error",
"translation": "Un canal avec ce pseudonyme existe déjà" "translation": "Un canal avec cet identifiant existe déjà"
}, },
{ {
"id": "store.sql_channel.update.previously.app_error", "id": "store.sql_channel.update.previously.app_error",
"translation": "Un canal avec ce pseudonyme a déjà été créé" "translation": "Un canal avec cet identifiant a déjà été créé"
}, },
{ {
"id": "store.sql_channel.update.updating.app_error", "id": "store.sql_channel.update.updating.app_error",
@@ -6544,15 +6544,15 @@
}, },
{ {
"id": "store.sql_post.query_max_post_size.error", "id": "store.sql_post.query_max_post_size.error",
"translation": "We couldn't determine the maximum supported post size" "translation": "Impossible de déterminer la taille maximale supportée pour les publications"
}, },
{ {
"id": "store.sql_post.query_max_post_size.max_post_size_bytes", "id": "store.sql_post.query_max_post_size.max_post_size_bytes",
"translation": "Post.Message supports at most %d characters (%d bytes)" "translation": "Post.Message supporte au maximum %d caractères (%d octets)"
}, },
{ {
"id": "store.sql_post.query_max_post_size.unrecognized_driver", "id": "store.sql_post.query_max_post_size.unrecognized_driver",
"translation": "No implementation found to determine the maximum supported post size" "translation": "Aucune implémentation trouvée pour déterminer la taille maximale supportée pour les publications"
}, },
{ {
"id": "store.sql_post.save.app_error", "id": "store.sql_post.save.app_error",
@@ -6680,31 +6680,31 @@
}, },
{ {
"id": "store.sql_role.get.app_error", "id": "store.sql_role.get.app_error",
"translation": "Impossible de récupérer le message" "translation": "Impossible de récupérer le rôle"
}, },
{ {
"id": "store.sql_role.get_by_name.app_error", "id": "store.sql_role.get_by_name.app_error",
"translation": "Impossible de récupérer le message" "translation": "Impossible de récupérer le rôle"
}, },
{ {
"id": "store.sql_role.get_by_names.app_error", "id": "store.sql_role.get_by_names.app_error",
"translation": "Impossible de récupérer le message" "translation": "Impossible de récupérer les rôles"
}, },
{ {
"id": "store.sql_role.permanent_delete_all.app_error", "id": "store.sql_role.permanent_delete_all.app_error",
"translation": "We could not permanently delete all the roles" "translation": "Impossible de supprimer définitivement tous les rôles"
}, },
{ {
"id": "store.sql_role.save.insert.app_error", "id": "store.sql_role.save.insert.app_error",
"translation": "Unable to save new role" "translation": "Impossible de sauvegarder le nouveau rôle"
}, },
{ {
"id": "store.sql_role.save.invalid_role.app_error", "id": "store.sql_role.save.invalid_role.app_error",
"translation": "The role was not valid" "translation": "Le rôle est invalide"
}, },
{ {
"id": "store.sql_role.save.update.app_error", "id": "store.sql_role.save.update.app_error",
"translation": "Impossible de récupérer le message" "translation": "Impossible de modifier le rôle"
}, },
{ {
"id": "store.sql_session.analytics_session_count.app_error", "id": "store.sql_session.analytics_session_count.app_error",
@@ -6812,7 +6812,7 @@
}, },
{ {
"id": "store.sql_system.permanent_delete_by_name.app_error", "id": "store.sql_system.permanent_delete_by_name.app_error",
"translation": "We could not permanently delete the system table entry" "translation": "Impossible de supprimer définitivement l'entrée de la table système"
}, },
{ {
"id": "store.sql_system.save.app_error", "id": "store.sql_system.save.app_error",
@@ -7288,11 +7288,11 @@
}, },
{ {
"id": "utils.file.list_directory.local.app_error", "id": "utils.file.list_directory.local.app_error",
"translation": "Une erreur s'est produite lors de l'affichage du répertoire du système de fichier local du serveur." "translation": "Une erreur s'est produite lors de l'affichage du dossier à partir du système de stockage local du serveur."
}, },
{ {
"id": "utils.file.list_directory.s3.app_error", "id": "utils.file.list_directory.s3.app_error",
"translation": "Une erreur s'est produite lors de l'affichage du répertoire S3." "translation": "Une erreur s'est produite lors de l'affichage du dossier à partir de S3."
}, },
{ {
"id": "utils.file.remove_directory.configured.app_error", "id": "utils.file.remove_directory.configured.app_error",
@@ -7300,11 +7300,11 @@
}, },
{ {
"id": "utils.file.remove_directory.local.app_error", "id": "utils.file.remove_directory.local.app_error",
"translation": "Une erreur s'est produite lors de la suppression du répertoire du stockage local du serveur." "translation": "Une erreur s'est produite lors de la suppression du dossier à partir du système de stockage local du serveur."
}, },
{ {
"id": "utils.file.remove_directory.s3.app_error", "id": "utils.file.remove_directory.s3.app_error",
"translation": "Une erreur s'est produite lors de la suppression du répertoire de S3." "translation": "Une erreur s'est produite lors de la suppression du dossier à partir de S3."
}, },
{ {
"id": "utils.file.remove_file.configured.app_error", "id": "utils.file.remove_file.configured.app_error",
@@ -7376,7 +7376,7 @@
}, },
{ {
"id": "utils.mail.sendMail.attachments.write_error", "id": "utils.mail.sendMail.attachments.write_error",
"translation": "Failed to write attachment to email" "translation": "Impossible d'attacher le fichier joint à l'e-mail"
}, },
{ {
"id": "utils.mail.send_mail.close.app_error", "id": "utils.mail.send_mail.close.app_error",
@@ -7384,7 +7384,7 @@
}, },
{ {
"id": "utils.mail.send_mail.from_address.app_error", "id": "utils.mail.send_mail.from_address.app_error",
"translation": "Error setting \"From Address\"" "translation": "Impossible de définir l'adresse source"
}, },
{ {
"id": "utils.mail.send_mail.msg.app_error", "id": "utils.mail.send_mail.msg.app_error",
@@ -7400,7 +7400,7 @@
}, },
{ {
"id": "utils.mail.send_mail.to_address.app_error", "id": "utils.mail.send_mail.to_address.app_error",
"translation": "Error setting \"To Address\"" "translation": "Impossible de définir l'adresse de destination"
}, },
{ {
"id": "utils.mail.test.configured.error", "id": "utils.mail.test.configured.error",

Просмотреть файл

@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Si è verificato un errore recuperando il gruppo"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Si è verificato un errore aggiornando l'icona del gruppo"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Impossibile attivare il plugin estratto. Il plugin può essere già disponibile e dev'essere attivato." "translation": "Impossibile attivate il plugin estratto."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Impossibile trovare i plugin attivi" "translation": "Impossibile trovare i plugin attivi"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "L'ID del plugin deve contenere meno di {{.Max}} caratteri."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Impossibile installare il plugin." "translation": "Impossibile installare il plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Impossibile installare il plugin. Un plugin con lo stesso ID è già installato." "translation": "Impossibile installare il plugin. Un plugin con lo stesso ID è già installato."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "L'id del plugin deve essere lungo almeno {{.Min}} caratteri, al massimo {{.Max}} caratteri e corrispondere a {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Impossibile trovare il manifest del plugin estratto" "translation": "Impossibile trovare il manifest del plugin estratto"

Просмотреть файл

@@ -517,7 +517,7 @@
}, },
{ {
"id": "api.command_away.name", "id": "api.command_away.name",
"translation": "離席" "translation": "離席"
}, },
{ {
"id": "api.command_away.success", "id": "api.command_away.success",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "チームの取得中にエラーが発生しました"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "チームアイコンの取得中にエラーが発生しました"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "抽出されたプラグインを有効化できませんでした。プラグインが既に存在し、有効化されている可能性があります。" "translation": "抽出されたプラグインを有効化できませんでした。"
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "有効なプラグインを取得できませんでした" "translation": "有効なプラグインを取得できませんでした"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "プラグインIDは{{.Max}}文字未満でなくてはなりません。"
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "プラグインをインストールできません。" "translation": "プラグインをインストールできません。"
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "プラグインをインストールできません。同じIDを持つプラグインがすでにインストールされています。" "translation": "プラグインをインストールできません。同じIDを持つプラグインがすでにインストールされています。"
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "プラグインIDは {{.Min}} 文字以上 {{.Max}} 文字以下で、{{.Regex}}にマッチしなければなりません。"
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "抽出されたプラグインのマニフェストが見付かりませんでした" "translation": "抽出されたプラグインのマニフェストが見付かりませんでした"

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "이 기본 채널은 전용 채널로 변환할 수 없습니다."
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "변환하기 위해 요청 된 채널은 이미 개인 채널입니다."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -557,7 +557,7 @@
}, },
{ {
"id": "api.command_channel_purpose.channel.app_error", "id": "api.command_channel_purpose.channel.app_error",
"translation": "현재 채널을 찾는 중 오류가 발생하였습니다." "translation": "채널 조회 중 오류가 발생하였습니다."
}, },
{ {
"id": "api.command_channel_purpose.desc", "id": "api.command_channel_purpose.desc",
@@ -569,11 +569,11 @@
}, },
{ {
"id": "api.command_channel_purpose.hint", "id": "api.command_channel_purpose.hint",
"translation": "[text]" "translation": "[문자]"
}, },
{ {
"id": "api.command_channel_purpose.message.app_error", "id": "api.command_channel_purpose.message.app_error",
"translation": "메시지는 /echo 명령어와 함께 제공되어야 합니다." "translation": "/purpose 명령어를 사용해서 메세지를 작성하세요."
}, },
{ {
"id": "api.command_channel_purpose.name", "id": "api.command_channel_purpose.name",
@@ -601,7 +601,7 @@
}, },
{ {
"id": "api.command_channel_rename.hint", "id": "api.command_channel_rename.hint",
"translation": "[text]" "translation": "[문자]"
}, },
{ {
"id": "api.command_channel_rename.message.app_error", "id": "api.command_channel_rename.message.app_error",
@@ -637,7 +637,7 @@
}, },
{ {
"id": "api.command_code.hint", "id": "api.command_code.hint",
"translation": "[text]" "translation": "[문자]"
}, },
{ {
"id": "api.command_code.message.app_error", "id": "api.command_code.message.app_error",
@@ -733,11 +733,11 @@
}, },
{ {
"id": "api.command_groupmsg.group_fail.app_error", "id": "api.command_groupmsg.group_fail.app_error",
"translation": "메시지 암호화 중 오류가 발생하였습니다." "translation": "그룹 메시지 생성 중 오류가 발생하였습니다."
}, },
{ {
"id": "api.command_groupmsg.hint", "id": "api.command_groupmsg.hint",
"translation": "@[username1],@[username2] 'message'" "translation": "@[username1],@[username2] '메시지'"
}, },
{ {
"id": "api.command_groupmsg.invalid_user.app_error", "id": "api.command_groupmsg.invalid_user.app_error",
@@ -752,7 +752,7 @@
}, },
{ {
"id": "api.command_groupmsg.list.app_error", "id": "api.command_groupmsg.list.app_error",
"translation": "사용자 제거 중 오류가 발생하였습니다." "translation": "사용자 조회 중 오류가 발생하였습니다."
}, },
{ {
"id": "api.command_groupmsg.max_users.app_error", "id": "api.command_groupmsg.max_users.app_error",
@@ -764,7 +764,7 @@
}, },
{ {
"id": "api.command_groupmsg.missing.app_error", "id": "api.command_groupmsg.missing.app_error",
"translation": "사용자를 찾을 수 없습니다" "translation": "해당 사용자를 찾을 수 없습니다."
}, },
{ {
"id": "api.command_groupmsg.name", "id": "api.command_groupmsg.name",
@@ -772,7 +772,7 @@
}, },
{ {
"id": "api.command_groupmsg.success", "id": "api.command_groupmsg.success",
"translation": "메세지를 보낸 유저." "translation": "메세지를 보낸 사용자 목록"
}, },
{ {
"id": "api.command_help.desc", "id": "api.command_help.desc",
@@ -784,51 +784,51 @@
}, },
{ {
"id": "api.command_invite.channel.app_error", "id": "api.command_invite.channel.app_error",
"translation": "현재 채널을 찾는 중 오류가 발생하였습니다." "translation": "현재 채널 조회 중 오류가 발생하였습니다."
}, },
{ {
"id": "api.command_invite.channel.error", "id": "api.command_invite.channel.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "{{.Channel}} 채널을 찾을 수 없습니다. 채널을 식별하려면 [채널 핸들] (https://about.mattermost.com/default-channel-handle-documentation) 을 사용하세요."
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "사용자를 채널에 초대 합니다."
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
"translation": "개인 메시지 채널에서 다른 사용자를 제거할 수 없습니다." "translation": "Direct Message 채널에서 사용자를 추가할 수 없습니다."
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
"translation": "채널에 참가하는 중 오류가 발생했습니다." "translation": "채널에 가입 중 오류가 발생했습니다."
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
"translation": "@[username] ~[channel]" "translation": "@[사용자 이름] ~[채널]"
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "사용자 이름 및 채널이 없습니다."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
"translation": "사용자를 찾을 수 없습니다" "translation": "해당 사용자를 찾을 수 없습니다"
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "초대"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "{{.Channel}} 에 {{.User}}를 추가할 권한이 없습니다."
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.Channel}} 채널에 {{.User}} 가 추가되었습니다."
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "채널에 이미 {{.User}} 가 있습니다."
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -840,7 +840,7 @@
}, },
{ {
"id": "api.command_join.hint", "id": "api.command_join.hint",
"translation": "~[channel]" "translation": "~[채널]"
}, },
{ {
"id": "api.command_join.list.app_error", "id": "api.command_join.list.app_error",
@@ -868,15 +868,15 @@
}, },
{ {
"id": "api.command_leave.fail.app_error", "id": "api.command_leave.fail.app_error",
"translation": "채널에 참가하는 중 오류가 발생했습니다." "translation": "채널에서 나가는 중 오류가 발생했습니다."
}, },
{ {
"id": "api.command_leave.list.app_error", "id": "api.command_leave.list.app_error",
"translation": "채널 목록을 나열하는 중 오류가 발생하였습니다." "translation": "채널 목록을 조회하는 중 오류가 발생하였습니다."
}, },
{ {
"id": "api.command_leave.missing.app_error", "id": "api.command_leave.missing.app_error",
"translation": "채널을 찾을 수 없습니다" "translation": "해당 채널을 찾을 수 없습니다"
}, },
{ {
"id": "api.command_leave.name", "id": "api.command_leave.name",
@@ -944,15 +944,15 @@
}, },
{ {
"id": "api.command_mute.desc", "id": "api.command_mute.desc",
"translation": "Turns off desktop, email and push notifications for the current channel or the [channel] specified." "translation": "지정된 현재 채널 또는[채널]에 대해 데스크 톱, 이메일 및 푸시 알림 기능을 해제합니다."
}, },
{ {
"id": "api.command_mute.error", "id": "api.command_mute.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "채널{{.Channel}} 을(를) 찾을 수 없습니다. 채널을 식별하려면[채널 핸들](https://about.mattermost.com/default-channel-handle-documentation) 을 사용하십시오."
}, },
{ {
"id": "api.command_mute.hint", "id": "api.command_mute.hint",
"translation": "~[channel]" "translation": "~[채널]"
}, },
{ {
"id": "api.command_mute.name", "id": "api.command_mute.name",
@@ -960,27 +960,27 @@
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "Could not find the specified channel. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "지정한 채널을 찾을 수 없습니다. 채널을 식별하려면[채널 핸들](https://about.mattermost.com/default-channel-handle-documentation)을 사용하십시오."
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "사용자가 멤버가 아니기 때문에 채널 {{.Channel}}의 음을 소거할 수 없습니다."
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
"translation": "You will not receive notifications for {{.Channel}} until channel mute is turned off." "translation": "채널 음소거가 해제될 때까지{{.Channel}}에 대한 알림을 받지 못 합니다."
}, },
{ {
"id": "api.command_mute.success_mute_direct_msg", "id": "api.command_mute.success_mute_direct_msg",
"translation": "You will not receive notifications for this channel until channel mute is turned off." "translation": "채널 음소거를 끄지 않으면 이 채널에 대한 알림을 받지 못 합니다."
}, },
{ {
"id": "api.command_mute.success_unmute", "id": "api.command_mute.success_unmute",
"translation": "{{.Channel}} is no longer muted." "translation": "{{.Channel}} 이 더 이상 음소거가 상태가 아닙니다."
}, },
{ {
"id": "api.command_mute.success_unmute_direct_msg", "id": "api.command_mute.success_unmute_direct_msg",
"translation": "This channel is no longer muted." "translation": "이 채널은 더 이상 음소거 상태가 아닙니다."
}, },
{ {
"id": "api.command_offline.desc", "id": "api.command_offline.desc",
@@ -1024,11 +1024,11 @@
}, },
{ {
"id": "api.command_remove.message.app_error", "id": "api.command_remove.message.app_error",
"translation": "메시지는 /echo 명령어와 함께 제공되어야 합니다." "translation": "/remove 혹은 /kick 명령어를 사용해서 메시지를 작성하세요."
}, },
{ {
"id": "api.command_remove.missing.app_error", "id": "api.command_remove.missing.app_error",
"translation": "사용자를 찾을 수 없습니다" "translation": "해당 사용자를 찾을 수 없습니다"
}, },
{ {
"id": "api.command_remove.name", "id": "api.command_remove.name",
@@ -1036,7 +1036,7 @@
}, },
{ {
"id": "api.command_remove.permission.app_error", "id": "api.command_remove.permission.app_error",
"translation": "당신은 채널 머릿말을 수정할 권한을 가지고 있지 않습니다." "translation": "멤버 삭제를 위한 적합한 권한을 가지고 있지 않습니다."
}, },
{ {
"id": "api.command_remove.user_not_in_channel", "id": "api.command_remove.user_not_in_channel",
@@ -1048,7 +1048,7 @@
}, },
{ {
"id": "api.command_search.hint", "id": "api.command_search.hint",
"translation": "[text]" "translation": "[문자]"
}, },
{ {
"id": "api.command_search.name", "id": "api.command_search.name",
@@ -1080,7 +1080,7 @@
}, },
{ {
"id": "api.command_shortcuts.unsupported.app_error", "id": "api.command_shortcuts.unsupported.app_error",
"translation": "당신의 기기에서는 검색 명령을 지원하지 않습니다" "translation": "당 기기에서 단축키를 지원하지 않습니다."
}, },
{ {
"id": "api.command_shrug.desc", "id": "api.command_shrug.desc",
@@ -1096,7 +1096,7 @@
}, },
{ {
"id": "api.compliance.init.debug", "id": "api.compliance.init.debug",
"translation": "명령어 API 경로 초기화 중" "translation": "API 경로 초기화 중"
}, },
{ {
"id": "api.config.client.old_format.app_error", "id": "api.config.client.old_format.app_error",
@@ -1176,7 +1176,7 @@
}, },
{ {
"id": "api.deprecated.init.debug", "id": "api.deprecated.init.debug",
"translation": "명령어 API 경로 초기화 중" "translation": "삭제 API 경로 초기화 중"
}, },
{ {
"id": "api.email_batching.add_notification_email_to_batch.channel_full.app_error", "id": "api.email_batching.add_notification_email_to_batch.channel_full.app_error",
@@ -1200,7 +1200,7 @@
}, },
{ {
"id": "api.email_batching.render_batched_post.direct_message", "id": "api.email_batching.render_batched_post.direct_message",
"translation": "Direct Message from " "translation": "로부터 직접 메시지"
}, },
{ {
"id": "api.email_batching.render_batched_post.go_to_post", "id": "api.email_batching.render_batched_post.go_to_post",
@@ -1208,11 +1208,11 @@
}, },
{ {
"id": "api.email_batching.render_batched_post.group_message", "id": "api.email_batching.render_batched_post.group_message",
"translation": "Group Message from " "translation": "로부터 그룹 메세지"
}, },
{ {
"id": "api.email_batching.render_batched_post.notification", "id": "api.email_batching.render_batched_post.notification",
"translation": "Notification from " "translation": "로부터 공지"
}, },
{ {
"id": "api.email_batching.render_batched_post.sender.app_error", "id": "api.email_batching.render_batched_post.sender.app_error",
@@ -1330,7 +1330,7 @@
}, },
{ {
"id": "api.file.get_file_preview.no_preview.app_error", "id": "api.file.get_file_preview.no_preview.app_error",
"translation": "파일 미리보기 이미지가 없습니다." "translation": "해당 파일 미리보기 기능이 없습니다."
}, },
{ {
"id": "api.file.get_file_thumbnail.no_thumbnail.app_error", "id": "api.file.get_file_thumbnail.no_thumbnail.app_error",
@@ -1342,7 +1342,7 @@
}, },
{ {
"id": "api.file.get_info_for_request.storage.app_error", "id": "api.file.get_info_for_request.storage.app_error",
"translation": "파일 정보를 가져올 수 없습니다. 이미지 저장소 설정되지 않았습니다." "translation": "파일 정보를 가져올 수 없습니다. 이미지 저장소 설정하세요."
}, },
{ {
"id": "api.file.get_public_file_old.storage.app_error", "id": "api.file.get_public_file_old.storage.app_error",
@@ -1538,15 +1538,15 @@
}, },
{ {
"id": "api.incoming_webhook.disabled.app_error", "id": "api.incoming_webhook.disabled.app_error",
"translation": "Incoming webhook은 관리자가 사용할 수 없게 설정했습니다." "translation": "시스템 관리자 권한으로 Incoming webhooks를 설정해야 합니다."
}, },
{ {
"id": "api.incoming_webhook.invalid_username.app_error", "id": "api.incoming_webhook.invalid_username.app_error",
"translation": "잘못된 유저이름입니다." "translation": "유효하지 않은 사용자 이름"
}, },
{ {
"id": "api.ldap.init.debug", "id": "api.ldap.init.debug",
"translation": "파일 API 경로 초기화 중" "translation": "LDAP API 경로 초기화 중"
}, },
{ {
"id": "api.license.add_license.array.app_error", "id": "api.license.add_license.array.app_error",
@@ -1586,7 +1586,7 @@
}, },
{ {
"id": "api.license.client.old_format.app_error", "id": "api.license.client.old_format.app_error",
"translation": "사용자 설정을 위한 새로운 형식은 아직 지원지 않습니다. 명령문에서 format=old 를 명시해 주세요." "translation": "클라이언트 라이선스를 위한 새로운 형식은 아직 지원지 않습니다. 명령문에서 format=old 를 명시해 주세요."
}, },
{ {
"id": "api.license.init.debug", "id": "api.license.init.debug",
@@ -1630,7 +1630,7 @@
}, },
{ {
"id": "api.oauth.delete.permissions.app_error", "id": "api.oauth.delete.permissions.app_error",
"translation": "OAuth2 앱을 삭제하기에 적절하지 않은 권한" "translation": "OAuth2 App 삭제를 위한 부적합한 권한"
}, },
{ {
"id": "api.oauth.get_access_token.bad_client_id.app_error", "id": "api.oauth.get_access_token.bad_client_id.app_error",
@@ -1694,7 +1694,7 @@
}, },
{ {
"id": "api.oauth.init.debug", "id": "api.oauth.init.debug",
"translation": "oauth API 경로 초기화 중" "translation": "OAuth API 경로 초기화 중"
}, },
{ {
"id": "api.oauth.invalid_state_token.app_error", "id": "api.oauth.invalid_state_token.app_error",
@@ -1738,23 +1738,23 @@
}, },
{ {
"id": "api.plugin.upload.array.app_error", "id": "api.plugin.upload.array.app_error",
"translation": "File array is empty in multipart/form request" "translation": "파일의 배열이 in multipart/from request 비어있습니다."
}, },
{ {
"id": "api.plugin.upload.file.app_error", "id": "api.plugin.upload.file.app_error",
"translation": "Unable to open file in multipart/form request" "translation": "파일을 in multipart/from request 열 수 없습니다."
}, },
{ {
"id": "api.plugin.upload.no_file.app_error", "id": "api.plugin.upload.no_file.app_error",
"translation": "Missing file in multipart/form request" "translation": "in multipart/form request 파일이 누락되었습니다."
}, },
{ {
"id": "api.post.check_for_out_of_channel_mentions.message.multiple", "id": "api.post.check_for_out_of_channel_mentions.message.multiple",
"translation": "{{.Usernames}}, {{.LastUsername}} 이 멘션되었으나, 그들은 이 채널에 속하지 않기 때문에 알림을 받지 못했습니다." "translation": "@{{.Usernames}} 와 @{{.LastUsername}} 에게 메시지는 전달했디만, 이 채널에 속하지 않기 때문에 알림을 받지 못했습니다."
}, },
{ {
"id": "api.post.check_for_out_of_channel_mentions.message.one", "id": "api.post.check_for_out_of_channel_mentions.message.one",
"translation": "{{.Username}}이 멘션되었으나, 그는 이 채널에 속하지 않기 때문에 알림을 받지 못했습니다." "translation": "@{{.Username}} 에게 메시지는 전달했지만, 이 채널에 속하지 않기 때문에 알림을 받지 못했습니다."
}, },
{ {
"id": "api.post.create_post.attach_files.error", "id": "api.post.create_post.attach_files.error",
@@ -1818,7 +1818,7 @@
}, },
{ {
"id": "api.post.do_action.action_id.app_error", "id": "api.post.do_action.action_id.app_error",
"translation": "잘못된 클라이언트 ID" "translation": "유효하지 않은 액션 ID"
}, },
{ {
"id": "api.post.do_action.action_integration.app_error", "id": "api.post.do_action.action_integration.app_error",
@@ -1868,7 +1868,7 @@
}, },
{ {
"id": "api.post.link_preview_disabled.app_error", "id": "api.post.link_preview_disabled.app_error",
"translation": "시스템 관리자가 개인 링크들 저장을 할 수 없도록 했습니다." "translation": "시스템 관리자 권한으로 Link previews를 활성화시키세요."
}, },
{ {
"id": "api.post.make_direct_channel_visible.get_2_members.error", "id": "api.post.make_direct_channel_visible.get_2_members.error",
@@ -1896,7 +1896,7 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.clear_push_notification.debug", "id": "api.post.send_notifications_and_forget.clear_push_notification.debug",
"translation": "Clearing push notification to %v with channel_id %v" "translation": "채널 ID %v 에 있는 %v 에게 전달한 푸쉬 메시지 삭제 중"
}, },
{ {
"id": "api.post.send_notifications_and_forget.files.error", "id": "api.post.send_notifications_and_forget.files.error",
@@ -1904,7 +1904,7 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.get_teams.error", "id": "api.post.send_notifications_and_forget.get_teams.error",
"translation": "Failed to get teams when sending cross-team DM user_id=%v, err=%v" "translation": "타 팀 사용자 (user_id=%v) 에게 DM 발송 중 팀 정보 조회 실패, err=%v"
}, },
{ {
"id": "api.post.send_notifications_and_forget.mention_subject", "id": "api.post.send_notifications_and_forget.mention_subject",
@@ -1912,15 +1912,15 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only", "id": "api.post.send_notifications_and_forget.push_image_only",
"translation": " uploaded one or more files in " "translation": "하나 이상의 파일이 업로드 되었습니다."
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only_dm", "id": "api.post.send_notifications_and_forget.push_image_only_dm",
"translation": " uploaded one or more files in a direct message" "translation": " 다이렉트 메시지에 하나 이상의 파일 업로드"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only_no_channel", "id": "api.post.send_notifications_and_forget.push_image_only_no_channel",
"translation": " uploaded one or more files" "translation": "하나 이상의 파일 업로드"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_in", "id": "api.post.send_notifications_and_forget.push_in",
@@ -1928,11 +1928,11 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_mention", "id": "api.post.send_notifications_and_forget.push_mention",
"translation": " mentioned you in " "translation": "~에서 메시지 전송~"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_mention_no_channel", "id": "api.post.send_notifications_and_forget.push_mention_no_channel",
"translation": " mentioned you in " "translation": "~에서 메시지 전송"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_message", "id": "api.post.send_notifications_and_forget.push_message",
@@ -1940,15 +1940,15 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_non_mention", "id": "api.post.send_notifications_and_forget.push_non_mention",
"translation": " posted in " "translation": "~에서 게시"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_non_mention_no_channel", "id": "api.post.send_notifications_and_forget.push_non_mention_no_channel",
"translation": " posted a message" "translation": "메세지 게시"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_notification.error", "id": "api.post.send_notifications_and_forget.push_notification.error",
"translation": "Failed to send push device_id={{.DeviceId}}, err={{.Error}}" "translation": "device_id={{.DeviceId}} 에 푸쉬 전달 실패, err={{.Error}}"
}, },
{ {
"id": "api.post.send_notifications_and_forget.sent", "id": "api.post.send_notifications_and_forget.sent",
@@ -1956,7 +1956,7 @@
}, },
{ {
"id": "api.post.update_mention_count_and_forget.update_error", "id": "api.post.update_mention_count_and_forget.update_error",
"translation": "Failed to update mention count, post_id=%v channel_id=%v err=%v" "translation": "멘션 수 변경 실패, post_id=%v channel_id=%v err=%v"
}, },
{ {
"id": "api.post.update_post.find.app_error", "id": "api.post.update_post.find.app_error",
@@ -1968,7 +1968,7 @@
}, },
{ {
"id": "api.post.update_post.permissions_denied.app_error", "id": "api.post.update_post.permissions_denied.app_error",
"translation": "새로운 팀을 생성할 수 없습니다. 시스템 관리자에게 문의해보세요." "translation": "게시 수정이 불가합니다. 시스템 관리자에게 문의세요."
}, },
{ {
"id": "api.post.update_post.permissions_details.app_error", "id": "api.post.update_post.permissions_details.app_error",
@@ -1976,7 +1976,7 @@
}, },
{ {
"id": "api.post.update_post.permissions_time_limit.app_error", "id": "api.post.update_post.permissions_time_limit.app_error",
"translation": "Post edit is only allowed for {{.timeLimit}} seconds. Please ask your systems administrator for details." "translation": "게시 수정은 {{.timeLimit}} 초 동안만 가능합니다. 상세한 내용은 시스템 관리자에게 문의하세요."
}, },
{ {
"id": "api.post.update_post.system_message.app_error", "id": "api.post.update_post.system_message.app_error",
@@ -2008,35 +2008,35 @@
}, },
{ {
"id": "api.reaction.delete_reaction.mismatched_channel_id.app_error", "id": "api.reaction.delete_reaction.mismatched_channel_id.app_error",
"translation": "Failed to delete reaction because channel ID does not match post ID in the URL" "translation": "URL에 있는 채널 ID 가 게시글 ID 와 맞지 않기 때문에 리액션 삭제 실패"
}, },
{ {
"id": "api.reaction.init.debug", "id": "api.reaction.init.debug",
"translation": "관리자 API 경로 초기화 중" "translation": "리액션 API 경로 초기화 중"
}, },
{ {
"id": "api.reaction.list_reactions.mismatched_channel_id.app_error", "id": "api.reaction.list_reactions.mismatched_channel_id.app_error",
"translation": "Failed to get reactions because channel ID does not match post ID in the URL" "translation": "URL 에서 채널 ID와 게시글 ID가 맞지 않아서 리액션 조회 실패"
}, },
{ {
"id": "api.reaction.save_reaction.invalid.app_error", "id": "api.reaction.save_reaction.invalid.app_error",
"translation": "Reaction is not valid." "translation": "리액션이 유효하지 않습니다."
}, },
{ {
"id": "api.reaction.save_reaction.mismatched_channel_id.app_error", "id": "api.reaction.save_reaction.mismatched_channel_id.app_error",
"translation": "Failed to save reaction because channel ID does not match post ID in the URL" "translation": "URL 에서 채널 ID와 게시글 ID가 맞지 않아서 리액션 저장 실패"
}, },
{ {
"id": "api.reaction.save_reaction.user_id.app_error", "id": "api.reaction.save_reaction.user_id.app_error",
"translation": "You cannot save reaction for the other user." "translation": "타 사용자에 대한 리액션 저장을 할 수 없습니다."
}, },
{ {
"id": "api.reaction.send_reaction_event.post.app_error", "id": "api.reaction.send_reaction_event.post.app_error",
"translation": "Failed to get post when sending websocket event for reaction" "translation": "리액션에 대한 웹소켓 이벤트 발송 중 게시글 조회 실패"
}, },
{ {
"id": "api.roles.patch_roles.license.error", "id": "api.roles.patch_roles.license.error",
"translation": "Your current license does not support advanced permissions." "translation": "지금 라이선스는 고급 퍼미션을 지원하지 않습니다."
}, },
{ {
"id": "api.saml.save_certificate.app_error", "id": "api.saml.save_certificate.app_error",
@@ -2048,11 +2048,11 @@
}, },
{ {
"id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt", "id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt",
"translation": "Must enable Forward80To443 when using LetsEncrypt" "translation": "LetsEncrypt를 사용하는 경우 Forward80To443 기능 활성화 필요"
}, },
{ {
"id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port", "id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port",
"translation": "Cannot forward port 80 to port 443 while listening on port %s: disable Forward80To443 if using a proxy server" "translation": "%s 포트에서 수신하는 중, 포트 80에서 포트 443으로 전환하지 못했습니다. 프록시 서버 사용 중인 경우 Forward80To443 옵션을 비활성화 해 주세요."
}, },
{ {
"id": "api.server.start_server.listening.info", "id": "api.server.start_server.listening.info",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated." "translation": "Unable to activate extracted plugin."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Unable to get active plugins" "translation": "Unable to get active plugins"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Plugin Id must be less than {{.Max}} characters."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Unable to install plugin." "translation": "Unable to install plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Unable to install plugin. A plugin with the same ID is already installed." "translation": "Unable to install plugin. A plugin with the same ID is already installed."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Unable to find manifest for extracted plugin" "translation": "Unable to find manifest for extracted plugin"

Просмотреть файл

@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated." "translation": "Unable to activate extracted plugin."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Unable to get active plugins" "translation": "Unable to get active plugins"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Plugin Id must be less than {{.Max}} characters."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Unable to install plugin." "translation": "Unable to install plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Unable to install plugin. A plugin with the same ID is already installed." "translation": "Unable to install plugin. A plugin with the same ID is already installed."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Unable to find manifest for extracted plugin" "translation": "Unable to find manifest for extracted plugin"

Просмотреть файл

@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated." "translation": "Unable to activate extracted plugin."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Nie udało się skasować reakcji" "translation": "Nie udało się skasować reakcji"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Plugin Id must be less than {{.Max}} characters."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Unable to install plugin." "translation": "Unable to install plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Unable to install plugin. A plugin with the same ID is already installed." "translation": "Unable to install plugin. A plugin with the same ID is already installed."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Unable to find manifest for extracted plugin" "translation": "Unable to find manifest for extracted plugin"

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "O canal padrão não pode ser convertido em um canal privado."
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "O canal selecionado para conversão já é um canal privado."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -792,7 +792,7 @@
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "Convide um usuário para o canal"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
@@ -808,7 +808,7 @@
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "Faltando Nome do Usuário e Canal."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Ocorreu um erro ao obter a equipe"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Ocorreu um erro ao atualizar o ícone da equipe"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "Não foi possível retornar a image de perfil, usuário não encontrado."
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "Conexão sem sucesso: {{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Não foi possível ativar o plugin extraído. O plugin já pode existir e estar ativado." "translation": "Não foi possível ativar o plugin extraído."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Não é possível obter os plugins ativos" "translation": "Não é possível obter os plugins ativos"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Id do plugin deve ter menos de {{.Max}} caracteres."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Não foi possível instalar o plugin." "translation": "Não foi possível instalar o plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Não foi possível instalar o plugin. Um plugin como o mesmo ID já está instalado." "translation": "Não foi possível instalar o plugin. Um plugin como o mesmo ID já está instalado."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "O Id do Plugin deve ter pelo menos {{.Min}} caracteres, e no máximo {{.Max}} caracteres e ser válido com {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Não foi possível encontrar o manifesto para o plugin extraído" "translation": "Não foi possível encontrar o manifesto para o plugin extraído"
@@ -6692,7 +6692,7 @@
}, },
{ {
"id": "store.sql_role.permanent_delete_all.app_error", "id": "store.sql_role.permanent_delete_all.app_error",
"translation": "We could not permanently delete all the roles" "translation": "Não podemos apagar permanentemente todas as funções"
}, },
{ {
"id": "store.sql_role.save.insert.app_error", "id": "store.sql_role.save.insert.app_error",
@@ -6812,7 +6812,7 @@
}, },
{ {
"id": "store.sql_system.permanent_delete_by_name.app_error", "id": "store.sql_system.permanent_delete_by_name.app_error",
"translation": "We could not permanently delete the system table entry" "translation": "Não podemos apagar permanentemente as entradas da tabela do sistema"
}, },
{ {
"id": "store.sql_system.save.app_error", "id": "store.sql_system.save.app_error",
@@ -7384,7 +7384,7 @@
}, },
{ {
"id": "utils.mail.send_mail.from_address.app_error", "id": "utils.mail.send_mail.from_address.app_error",
"translation": "Error setting \"From Address\"" "translation": "Erro em configurar \"From Address\""
}, },
{ {
"id": "utils.mail.send_mail.msg.app_error", "id": "utils.mail.send_mail.msg.app_error",
@@ -7400,7 +7400,7 @@
}, },
{ {
"id": "utils.mail.send_mail.to_address.app_error", "id": "utils.mail.send_mail.to_address.app_error",
"translation": "Error setting \"To Address\"" "translation": "Erro em configurar \"To Address\""
}, },
{ {
"id": "utils.mail.test.configured.error", "id": "utils.mail.test.configured.error",

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "Канал по умолчанию не может быть преобразован в частный. "
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "Канал, запрошенный для преобразования, уже является частным каналом."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -257,7 +257,7 @@
}, },
{ {
"id": "api.channel.delete_channel.archived", "id": "api.channel.delete_channel.archived",
"translation": "%v переместил канал в архив." "translation": "%v архивация канала."
}, },
{ {
"id": "api.channel.delete_channel.cannot.app_error", "id": "api.channel.delete_channel.cannot.app_error",
@@ -788,11 +788,11 @@
}, },
{ {
"id": "api.command_invite.channel.error", "id": "api.command_invite.channel.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Не удалось найти канал {{.Channel}}. Для идентификации каналов используйте [название канала] (https://about.mattermost.com/default-channel-handle-documentation)."
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "Пригласить пользователя в канал"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
@@ -800,35 +800,35 @@
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
"translation": "Во время присоединения к каналу произошла ошибка." "translation": "При подключении к каналу произошла ошибка."
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
"translation": "@[username] ~[channel]" "translation": "@[имя пользователя] ~[канал]"
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "Отсутствует имя пользователя и канал."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
"translation": "Не удалось найти пользователя" "translation": "Мы не смогли найти пользователя."
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "Пригласить"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "У вас недостаточно прав для добавления {{.User}} в {{.Channel}}."
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.User}} добавлен в канал {{.Channel}}."
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "{{.User}} уже находится в канале."
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -840,7 +840,7 @@
}, },
{ {
"id": "api.command_join.hint", "id": "api.command_join.hint",
"translation": "~[channel]" "translation": "канал"
}, },
{ {
"id": "api.command_join.list.app_error", "id": "api.command_join.list.app_error",
@@ -944,43 +944,43 @@
}, },
{ {
"id": "api.command_mute.desc", "id": "api.command_mute.desc",
"translation": "Turns off desktop, email and push notifications for the current channel or the [channel] specified." "translation": "Отключить уведомления на рабочем столе, электронной почте и push для текущего или указанного канала [канала]."
}, },
{ {
"id": "api.command_mute.error", "id": "api.command_mute.error",
"translation": "Could not find the channel {{.Channel}}. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Не удалось найти канал {{.Channel}}. Пожалуйста, используйте [дескриптор канала] (https://about.mattermost.com/default-channel-handle-documentation) для идентификации каналов."
}, },
{ {
"id": "api.command_mute.hint", "id": "api.command_mute.hint",
"translation": "~[channel]" "translation": "канал"
}, },
{ {
"id": "api.command_mute.name", "id": "api.command_mute.name",
"translation": "mute" "translation": "выкл"
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "Could not find the specified channel. Please use the [channel handle](https://about.mattermost.com/default-channel-handle-documentation) to identify channels." "translation": "Не удалось найти указанный канал. Пожалуйста, используйте [дескриптор канала] (https://about.mattermost.com/default-channel-handle-documentation) для идентификации каналов."
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "Не удалось отключить канал {{.Channel}}, поскольку вы не являетесь его членом."
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
"translation": "You will not receive notifications for {{.Channel}} until channel mute is turned off." "translation": "Вы не будете получать уведомления для {{.Channel}} до тех пор, пока отключен звук."
}, },
{ {
"id": "api.command_mute.success_mute_direct_msg", "id": "api.command_mute.success_mute_direct_msg",
"translation": "You will not receive notifications for this channel until channel mute is turned off." "translation": "Вы не будете получать уведомления для этого канала до тех пор, пока отключен звук."
}, },
{ {
"id": "api.command_mute.success_unmute", "id": "api.command_mute.success_unmute",
"translation": "{{.Channel}} is no longer muted." "translation": "{{.Channel}} больше не отключен."
}, },
{ {
"id": "api.command_mute.success_unmute_direct_msg", "id": "api.command_mute.success_unmute_direct_msg",
"translation": "This channel is no longer muted." "translation": "Этот канал больше не отключен."
}, },
{ {
"id": "api.command_offline.desc", "id": "api.command_offline.desc",
@@ -1478,7 +1478,7 @@
}, },
{ {
"id": "api.file.upload_file.incorrect_number_of_files.app_error", "id": "api.file.upload_file.incorrect_number_of_files.app_error",
"translation": "Unable to upload files. Incorrect number of files specified." "translation": "Не удалось загрузить файлы. Неверное количество указанных файлов."
}, },
{ {
"id": "api.file.upload_file.large_image.app_error", "id": "api.file.upload_file.large_image.app_error",
@@ -1916,7 +1916,7 @@
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only_dm", "id": "api.post.send_notifications_and_forget.push_image_only_dm",
"translation": " Загружены один или несколько файлов для сообщения" "translation": " Загружены один или несколько файлов для текущего сообщения"
}, },
{ {
"id": "api.post.send_notifications_and_forget.push_image_only_no_channel", "id": "api.post.send_notifications_and_forget.push_image_only_no_channel",
@@ -2048,11 +2048,11 @@
}, },
{ {
"id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt", "id": "api.server.start_server.forward80to443.disabled_while_using_lets_encrypt",
"translation": "Must enable Forward80To443 when using LetsEncrypt" "translation": "Необходимо перенаправлять 80 на 443 при использовании LetsEncrypt"
}, },
{ {
"id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port", "id": "api.server.start_server.forward80to443.enabled_but_listening_on_wrong_port",
"translation": "Cannot forward port 80 to port 443 while listening on port %s: disable Forward80To443 if using a proxy server" "translation": "Не удается переправить порт 80 на порт 443 во время прослушивания порта %s: отключить переадресацию 80 до 443 при использовании прокси-сервера"
}, },
{ {
"id": "api.server.start_server.listening.info", "id": "api.server.start_server.listening.info",
@@ -2100,7 +2100,7 @@
}, },
{ {
"id": "api.slackimport.slack_add_bot_user.unable_import", "id": "api.slackimport.slack_add_bot_user.unable_import",
"translation": "Unable to import the Integration/Slack Bot user {{.Username}}.\r\n" "translation": "Не удалось импортировать пользователя Integration / Slack Bot {{.Username}}.\r\n"
}, },
{ {
"id": "api.slackimport.slack_add_channels.added", "id": "api.slackimport.slack_add_channels.added",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Произошла ошибка при подключении команды"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2452,19 +2452,19 @@
}, },
{ {
"id": "api.team.set_team_icon.decode.app_error", "id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon" "translation": "Не удалось декодировать поток."
}, },
{ {
"id": "api.team.set_team_icon.decode_config.app_error", "id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata" "translation": "Не удалось декодировать метаданные поток команды"
}, },
{ {
"id": "api.team.set_team_icon.encode.app_error", "id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon" "translation": "Не удалось закодировать поток."
}, },
{ {
"id": "api.team.set_team_icon.get_team.app_error", "id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Произошла ошибка при подключении команды"
}, },
{ {
"id": "api.team.set_team_icon.no_file.app_error", "id": "api.team.set_team_icon.no_file.app_error",
@@ -2472,7 +2472,7 @@
}, },
{ {
"id": "api.team.set_team_icon.open.app_error", "id": "api.team.set_team_icon.open.app_error",
"translation": "Не могу открыть файл изображения" "translation": "Не удалось открыть файл"
}, },
{ {
"id": "api.team.set_team_icon.parse.app_error", "id": "api.team.set_team_icon.parse.app_error",
@@ -2488,7 +2488,7 @@
}, },
{ {
"id": "api.team.set_team_icon.write_file.app_error", "id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon" "translation": "Не удалось установить значок"
}, },
{ {
"id": "api.team.signup_team.email_disabled.app_error", "id": "api.team.signup_team.email_disabled.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Во время создания метки произошла ошибка:"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2680,11 +2680,11 @@
}, },
{ {
"id": "api.templates.user_access_token_body.info", "id": "api.templates.user_access_token_body.info",
"translation": "A personal access token was added to your account on {{ .SiteURL }}. They can be used to access {{.SiteName}} with your account.<br>If this change wasn't initiated by you, please contact your system administrator." "translation": "В ваш аккаунт добавлен токен доступа. {{.SiteURL}}. Они могут использоваться для доступа к {{.SiteName}} в вашей учетной записи. <br> Если это изменение не было инициировано вами, обратитесь к системному администратору."
}, },
{ {
"id": "api.templates.user_access_token_body.title", "id": "api.templates.user_access_token_body.title",
"translation": "Personal access token added to your account" "translation": "Личный ключ доступа, добавленный в вашу учетную запись"
}, },
{ {
"id": "api.templates.user_access_token_subject", "id": "api.templates.user_access_token_subject",
@@ -2860,7 +2860,7 @@
}, },
{ {
"id": "api.user.create_user.missing_token.app_error", "id": "api.user.create_user.missing_token.app_error",
"translation": "Missing Token." "translation": "Отсутствует токен."
}, },
{ {
"id": "api.user.create_user.no_open_server", "id": "api.user.create_user.no_open_server",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "Не удалось получить изображение профиля, пользователь не найден."
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3052,7 +3052,7 @@
}, },
{ {
"id": "api.user.send_user_access_token.error", "id": "api.user.send_user_access_token.error",
"translation": "Во время отправки сообщения с токеном доступа произошли ошибки" "translation": "Не удалось отправить сообщение «Личный доступ по токенам»"
}, },
{ {
"id": "api.user.send_verify_email_and_forget.failed.error", "id": "api.user.send_verify_email_and_forget.failed.error",
@@ -3244,7 +3244,7 @@
}, },
{ {
"id": "api.webhook.incoming.error", "id": "api.webhook.incoming.error",
"translation": "Could not decode the multipart payload of incoming webhook." "translation": "Не удалось декодировать многостраничную полезную нагрузку входящего вебхука"
}, },
{ {
"id": "api.webhook.init.debug", "id": "api.webhook.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "Соединение неудачно: {{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3496,7 +3496,7 @@
}, },
{ {
"id": "app.import.validate_direct_channel_import_data.unknown_favoriter.error", "id": "app.import.validate_direct_channel_import_data.unknown_favoriter.error",
"translation": "Direct channel can only be favorited by members. \"{{.Username}}\" is not a member." "translation": "Текущий канал может быть добавлен в избранное только членами команды. \"{{.Username}}\" не является членом данной команды."
}, },
{ {
"id": "app.import.validate_direct_post_import_data.channel_members_required.error", "id": "app.import.validate_direct_post_import_data.channel_members_required.error",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated." "translation": "Unable to activate extracted plugin."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Не удалось получить активные плагины" "translation": "Не удалось получить активные плагины"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Plugin Id must be less than {{.Max}} characters."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Unable to install plugin." "translation": "Unable to install plugin."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Unable to install plugin. A plugin with the same ID is already installed." "translation": "Unable to install plugin. A plugin with the same ID is already installed."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Plugin Id must be at least {{.Min}} characters, at most {{.Max}} characters and match {{.Regex}}."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Unable to find manifest for extracted plugin" "translation": "Unable to find manifest for extracted plugin"

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "Bu varsayılan kanal özel bir kanala dönüştürülemez."
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "Dönüştürmek istediğiniz kanal zaten özel bir kanal."
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -788,19 +788,19 @@
}, },
{ {
"id": "api.command_invite.channel.error", "id": "api.command_invite.channel.error",
"translation": "{{.Channel}} kanalı belirlenemedi. Lütfen kanalları belirtmek için [channel handle](https://about.mattermost.com/default-channel-handle-documentation) kullanın." "translation": "{{.Channel}} kanalı belirlenemedi. Lütfen kanalları belirtmek için [channel handle] kullanın (https://about.mattermost.com/default-channel-handle-documentation)."
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "Bir kanala bir kullanıcı çağır"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
"translation": "Bir kişiyi doğrudan ileti kanalından çıkaramazsınız." "translation": "Bir kişiyi doğrudan ileti kanalına ekleyemezsiniz."
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
"translation": "Kanala katılınılırken bir sorun çıktı." "translation": "Kanala katılma sırasında bir sorun çıktı."
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
@@ -808,7 +808,7 @@
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "Kullanıcı Adı ya da Kanal eksik."
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
@@ -816,19 +816,19 @@
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "çağır"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "{{.User}} kullanıcısını {{.Channel}} kanalına eklemek için yeterli izinleriniz yok."
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "{{.User}} kullanıcısı {{.Channel}} kanalına eklendi."
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "{{.User}} zaten kanalda."
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -960,11 +960,11 @@
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "{{.Channel}} kanalı belirlenemedi. Lütfen kanalları belirtmek için [channel handle](https://about.mattermost.com/default-channel-handle-documentation) kullanın." "translation": "Belirtilen kanal bulunamadı. Lütfen kanalları belirtmek için [channel handle] kullanın (https://about.mattermost.com/default-channel-handle-documentation)."
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "Üyesi olmadığınızdan {{.Channel}} kanalının bildirimlerini kapatamazsınız."
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "Takım alınırken bir sorun çıktı"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "Takım simgesi güncellenirken bir sorun çıktı"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2628,7 +2628,7 @@
}, },
{ {
"id": "api.templates.reset_body.info", "id": "api.templates.reset_body.info",
"translation": "Parolanızı sıfırlamak için aşağıdaki \"Parolayı Sıfırla\" üzerine tıklayın.<br>Parola sıfırlama isteğinde bulunmadıysanız bu e-posta yoksayın böylece parolanız değiştirilmez. Parola sıfırlama bağlantısı 24 saat sonra geçersiz olur." "translation": "Parolanızı sıfırlamak için aşağıdaki \"Parolayı Sıfırla\" üzerine tıklayın.<br>Parola sıfırlama isteğinde bulunmadıysanız bu e-posta yok sayın böylece parolanız değiştirilmez. Parola sıfırlama bağlantısı 24 saat sonra geçersiz olur."
}, },
{ {
"id": "api.templates.reset_body.title", "id": "api.templates.reset_body.title",
@@ -2860,7 +2860,7 @@
}, },
{ {
"id": "api.user.create_user.missing_token.app_error", "id": "api.user.create_user.missing_token.app_error",
"translation": "Missing Token." "translation": "Kod Eksik."
}, },
{ {
"id": "api.user.create_user.no_open_server", "id": "api.user.create_user.no_open_server",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "Profil görseli alınamadı, kullanıcı bulunamadı."
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "Bağlantı kurulamadı: {{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "Ayıklanan uygulama eki etkinleştirilemedi. Uygulama eki zaten var ve etkinleştirilmiş olabilir." "translation": "Ayıklanan uygulama eki etkinleştirilemedi."
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "Etkin uygulama ekleri alınamadı" "translation": "Etkin uygulama ekleri alınamadı"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "Uygulama eki kodu {{.Max}} karakterden kısa olmalıdır."
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "Uygulama eki kurulamadı." "translation": "Uygulama eki kurulamadı."
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "Uygulama eki kurulamadı. Aynı kodu taşıyan bir uygulama eki zaten var." "translation": "Uygulama eki kurulamadı. Aynı kodu taşıyan bir uygulama eki zaten var."
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "Uygulama eki kodu {{.Min}} ile {{.Max}} karakter arasında olmalı ve {{.Regex}}. ile uyumlu olmalıdır."
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "Ayıklanan uygulama eki bilgi dosyası bulunamadı" "translation": "Ayıklanan uygulama eki bilgi dosyası bulunamadı"
@@ -6692,7 +6692,7 @@
}, },
{ {
"id": "store.sql_role.permanent_delete_all.app_error", "id": "store.sql_role.permanent_delete_all.app_error",
"translation": "We could not permanently delete all the roles" "translation": "Tüm roller kalıcı olarak silinemedi"
}, },
{ {
"id": "store.sql_role.save.insert.app_error", "id": "store.sql_role.save.insert.app_error",
@@ -6812,7 +6812,7 @@
}, },
{ {
"id": "store.sql_system.permanent_delete_by_name.app_error", "id": "store.sql_system.permanent_delete_by_name.app_error",
"translation": "We could not permanently delete the system table entry" "translation": "Sistem tablosu kaydı kalıcı olarak silinemedi"
}, },
{ {
"id": "store.sql_system.save.app_error", "id": "store.sql_system.save.app_error",
@@ -7384,7 +7384,7 @@
}, },
{ {
"id": "utils.mail.send_mail.from_address.app_error", "id": "utils.mail.send_mail.from_address.app_error",
"translation": "Error setting \"From Address\"" "translation": "\"Kimden\" adresi ayarlanırken sorun çıktı"
}, },
{ {
"id": "utils.mail.send_mail.msg.app_error", "id": "utils.mail.send_mail.msg.app_error",
@@ -7400,7 +7400,7 @@
}, },
{ {
"id": "utils.mail.send_mail.to_address.app_error", "id": "utils.mail.send_mail.to_address.app_error",
"translation": "Error setting \"To Address\"" "translation": "\"Kime\" adresi ayarlanırken sorun çıktı"
}, },
{ {
"id": "utils.mail.test.configured.error", "id": "utils.mail.test.configured.error",

Просмотреть файл

@@ -685,7 +685,7 @@
}, },
{ {
"id": "api.command_echo.delay.app_error", "id": "api.command_echo.delay.app_error",
"translation": "延迟必须在10000秒内" "translation": "延迟必须在 10000 秒内"
}, },
{ {
"id": "api.command_echo.desc", "id": "api.command_echo.desc",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "获取团队时发生错误"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "更新团队图标时发生错误"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "无法激活揭开的插件。插件可能已存在并已激活。" "translation": "无法激活解压的插件。"
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "无法获取已启动的插件" "translation": "无法获取已启动的插件"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "插件 Id 必须小于 {{.Max}} 个字符。"
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "无法安装插件。" "translation": "无法安装插件。"
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "无法安装插件。已存在相同 ID 的插件。" "translation": "无法安装插件。已存在相同 ID 的插件。"
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "插件 Id 必须至少 {{.Min}} 个字符,最多 {{.Max}} 个字符并匹配 {{.Regex}}。"
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "无法在解压的插件里找到 manifest 档" "translation": "无法在解压的插件里找到 manifest 档"
@@ -4120,7 +4120,7 @@
}, },
{ {
"id": "ent.compliance.run_limit.warning", "id": "ent.compliance.run_limit.warning",
"translation": "任务'{{.JobName}}'的导出审核警告:'{{.FilePath}}'过多行返回截断至第30,000行" "translation": "任务 '{{.JobName}}' 的导出审核警告:'{{.FilePath}}' 过多行返回截断至第 3,0000 行"
}, },
{ {
"id": "ent.compliance.run_started.info", "id": "ent.compliance.run_started.info",

Просмотреть файл

@@ -217,11 +217,11 @@
}, },
{ {
"id": "api.channel.convert_channel_to_private.default_channel_error", "id": "api.channel.convert_channel_to_private.default_channel_error",
"translation": "This default channel cannot be converted into a private channel." "translation": "預設頻道不能轉換為私人頻道。"
}, },
{ {
"id": "api.channel.convert_channel_to_private.private_channel_error", "id": "api.channel.convert_channel_to_private.private_channel_error",
"translation": "The channel requested to convert is already a private channel." "translation": "要求轉換的頻道已為私人頻道。"
}, },
{ {
"id": "api.channel.create_channel.direct_channel.app_error", "id": "api.channel.create_channel.direct_channel.app_error",
@@ -792,11 +792,11 @@
}, },
{ {
"id": "api.command_invite.desc", "id": "api.command_invite.desc",
"translation": "Invite a user to a channel" "translation": "邀請使用者至頻道"
}, },
{ {
"id": "api.command_invite.directchannel.app_error", "id": "api.command_invite.directchannel.app_error",
"translation": "無法成員直接通訊頻道中移除。" "translation": "無法新增成員直接通訊頻道。"
}, },
{ {
"id": "api.command_invite.fail.app_error", "id": "api.command_invite.fail.app_error",
@@ -804,11 +804,11 @@
}, },
{ {
"id": "api.command_invite.hint", "id": "api.command_invite.hint",
"translation": "@[username] ~[channel]" "translation": "@[使用者] ~[頻道]"
}, },
{ {
"id": "api.command_invite.missing_message.app_error", "id": "api.command_invite.missing_message.app_error",
"translation": "Missing Username and Channel." "translation": "缺少使用者名稱跟頻道。"
}, },
{ {
"id": "api.command_invite.missing_user.app_error", "id": "api.command_invite.missing_user.app_error",
@@ -816,19 +816,19 @@
}, },
{ {
"id": "api.command_invite.name", "id": "api.command_invite.name",
"translation": "invite" "translation": "邀請"
}, },
{ {
"id": "api.command_invite.permission.app_error", "id": "api.command_invite.permission.app_error",
"translation": "You don't have enough permissions to add {{.User}} in {{.Channel}}." "translation": "沒有足夠的權限將 {{.User}} 新增至 {{.Channel}}"
}, },
{ {
"id": "api.command_invite.success", "id": "api.command_invite.success",
"translation": "{{.User}} added to {{.Channel}} channel." "translation": "已將 {{.User}} 新增至 {{.Channel}} 頻道。"
}, },
{ {
"id": "api.command_invite.user_already_in_channel.app_error", "id": "api.command_invite.user_already_in_channel.app_error",
"translation": "{{.User}} is already in the channel." "translation": "{{.User}} 已在頻道當中。"
}, },
{ {
"id": "api.command_join.desc", "id": "api.command_join.desc",
@@ -960,11 +960,11 @@
}, },
{ {
"id": "api.command_mute.no_channel.error", "id": "api.command_mute.no_channel.error",
"translation": "找不到頻道 {{.Channel}}. 請用[頻道識別](https://about.mattermost.com/default-channel-handle-documentation)以分辨頻道。" "translation": "找不到特定的頻道。 請用[頻道識別](https://about.mattermost.com/default-channel-handle-documentation)以分辨頻道。"
}, },
{ {
"id": "api.command_mute.not_member.error", "id": "api.command_mute.not_member.error",
"translation": "Could not mute channel {{.Channel}} as you are not a member." "translation": "由於不是頻道成員,無法對頻道 {{.Channel}} 靜音。"
}, },
{ {
"id": "api.command_mute.success_mute", "id": "api.command_mute.success_mute",
@@ -2436,7 +2436,7 @@
}, },
{ {
"id": "api.team.remove_team_icon.get_team.app_error", "id": "api.team.remove_team_icon.get_team.app_error",
"translation": "An error occurred getting the team" "translation": "取得團隊時發生錯誤"
}, },
{ {
"id": "api.team.remove_user_from_team.missing.app_error", "id": "api.team.remove_user_from_team.missing.app_error",
@@ -2496,7 +2496,7 @@
}, },
{ {
"id": "api.team.team_icon.update.app_error", "id": "api.team.team_icon.update.app_error",
"translation": "An error occurred updating the team icon" "translation": "更新團隊時發生錯誤"
}, },
{ {
"id": "api.team.update_member_roles.not_a_member", "id": "api.team.update_member_roles.not_a_member",
@@ -2860,7 +2860,7 @@
}, },
{ {
"id": "api.user.create_user.missing_token.app_error", "id": "api.user.create_user.missing_token.app_error",
"translation": "Missing Token." "translation": "缺少 Token"
}, },
{ {
"id": "api.user.create_user.no_open_server", "id": "api.user.create_user.no_open_server",
@@ -2912,7 +2912,7 @@
}, },
{ {
"id": "api.user.get_profile_image.not_found.app_error", "id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found." "translation": "無法取得個人圖像,找不到使用者。"
}, },
{ {
"id": "api.user.init.debug", "id": "api.user.init.debug",
@@ -3308,7 +3308,7 @@
}, },
{ {
"id": "app.admin.test_email.failure", "id": "app.admin.test_email.failure",
"translation": "Connection unsuccessful: {{.Error}}" "translation": "連線失敗:{{.Error}}"
}, },
{ {
"id": "app.channel.create_channel.no_team_id.app_error", "id": "app.channel.create_channel.no_team_id.app_error",
@@ -3812,7 +3812,7 @@
}, },
{ {
"id": "app.plugin.activate.app_error", "id": "app.plugin.activate.app_error",
"translation": "無法啟已解開的模組。模組可能已存在並已啟動。" "translation": "無法啟已解開的模組。"
}, },
{ {
"id": "app.plugin.cluster.save_config.app_error", "id": "app.plugin.cluster.save_config.app_error",
@@ -3846,10 +3846,6 @@
"id": "app.plugin.get_plugins.app_error", "id": "app.plugin.get_plugins.app_error",
"translation": "無法取得啟用的模組" "translation": "無法取得啟用的模組"
}, },
{
"id": "app.plugin.id_length.app_error",
"translation": "模組 ID 必須少於 {{.Max}} 字元。"
},
{ {
"id": "app.plugin.install.app_error", "id": "app.plugin.install.app_error",
"translation": "無法安裝模組。" "translation": "無法安裝模組。"
@@ -3858,6 +3854,10 @@
"id": "app.plugin.install_id.app_error", "id": "app.plugin.install_id.app_error",
"translation": "無法安裝模組。已安裝了相同 ID 的模組。" "translation": "無法安裝模組。已安裝了相同 ID 的模組。"
}, },
{
"id": "app.plugin.invalid_id.app_error",
"translation": "模組 ID 至少需 {{.Min}} 字元,最多可為 {{.Max}} 且符合 {{.Regex}}。"
},
{ {
"id": "app.plugin.manifest.app_error", "id": "app.plugin.manifest.app_error",
"translation": "已解開的模組中找不到資訊清單" "translation": "已解開的模組中找不到資訊清單"
@@ -6692,7 +6692,7 @@
}, },
{ {
"id": "store.sql_role.permanent_delete_all.app_error", "id": "store.sql_role.permanent_delete_all.app_error",
"translation": "We could not permanently delete all the roles" "translation": "無法永久刪除所有的角色"
}, },
{ {
"id": "store.sql_role.save.insert.app_error", "id": "store.sql_role.save.insert.app_error",
@@ -6812,7 +6812,7 @@
}, },
{ {
"id": "store.sql_system.permanent_delete_by_name.app_error", "id": "store.sql_system.permanent_delete_by_name.app_error",
"translation": "We could not permanently delete the system table entry" "translation": "無法永久刪除系統表單當中的項目"
}, },
{ {
"id": "store.sql_system.save.app_error", "id": "store.sql_system.save.app_error",
@@ -7384,7 +7384,7 @@
}, },
{ {
"id": "utils.mail.send_mail.from_address.app_error", "id": "utils.mail.send_mail.from_address.app_error",
"translation": "Error setting \"From Address\"" "translation": "無法設定寄件人地址"
}, },
{ {
"id": "utils.mail.send_mail.msg.app_error", "id": "utils.mail.send_mail.msg.app_error",
@@ -7400,7 +7400,7 @@
}, },
{ {
"id": "utils.mail.send_mail.to_address.app_error", "id": "utils.mail.send_mail.to_address.app_error",
"translation": "Error setting \"To Address\"" "translation": "無法設定收件人地址"
}, },
{ {
"id": "utils.mail.test.configured.error", "id": "utils.mail.test.configured.error",

50
mlog/default.go Обычный файл
Просмотреть файл

@@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package mlog
import (
"encoding/json"
"fmt"
)
// defaultLog manually encodes the log to STDOUT, providing a basic, default logging implementation
// before mlog is fully configured.
func defaultLog(level, msg string, fields ...Field) {
log := struct {
Level string `json:"level"`
Message string `json:"msg"`
Fields []Field `json:"fields,omitempty"`
}{
level,
msg,
fields,
}
if b, err := json.Marshal(log); err != nil {
fmt.Printf(`{"level":"error","msg":"failed to encode log message"}%s`, "\n")
} else {
fmt.Printf("%s\n", b)
}
}
func defaultDebugLog(msg string, fields ...Field) {
defaultLog("debug", msg, fields...)
}
func defaultInfoLog(msg string, fields ...Field) {
defaultLog("info", msg, fields...)
}
func defaultWarnLog(msg string, fields ...Field) {
defaultLog("warn", msg, fields...)
}
func defaultErrorLog(msg string, fields ...Field) {
defaultLog("error", msg, fields...)
}
func defaultCriticalLog(msg string, fields ...Field) {
// We map critical to error in zap, so be consistent.
defaultLog("error", msg, fields...)
}

Просмотреть файл

@@ -35,8 +35,8 @@ func GloballyEnableDebugLogForTest() {
globalLogger.consoleLevel.SetLevel(zapcore.DebugLevel) globalLogger.consoleLevel.SetLevel(zapcore.DebugLevel)
} }
var Debug LogFunc var Debug LogFunc = defaultDebugLog
var Info LogFunc var Info LogFunc = defaultInfoLog
var Warn LogFunc var Warn LogFunc = defaultWarnLog
var Error LogFunc var Error LogFunc = defaultErrorLog
var Critical LogFunc var Critical LogFunc = defaultCriticalLog

143
mlog/global_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,143 @@
package mlog_test
import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/mlog"
)
func TestLoggingBeforeInitialized(t *testing.T) {
require.NotPanics(t, func() {
// None of these should segfault before mlog is globally configured
mlog.Info("info log")
mlog.Debug("debug log")
mlog.Warn("warning log")
mlog.Error("error log")
mlog.Critical("critical log")
})
}
func TestLoggingAfterInitialized(t *testing.T) {
testCases := []struct {
Description string
LoggerConfiguration *mlog.LoggerConfiguration
ExpectedLogs []string
}{
{
"file logging, json, debug",
&mlog.LoggerConfiguration{
EnableConsole: false,
EnableFile: true,
FileJson: true,
FileLevel: mlog.LevelDebug,
},
[]string{
`{"level":"debug","ts":0,"caller":"mlog/global_test.go:0","msg":"real debug log"}`,
`{"level":"info","ts":0,"caller":"mlog/global_test.go:0","msg":"real info log"}`,
`{"level":"warn","ts":0,"caller":"mlog/global_test.go:0","msg":"real warning log"}`,
`{"level":"error","ts":0,"caller":"mlog/global_test.go:0","msg":"real error log"}`,
`{"level":"error","ts":0,"caller":"mlog/global_test.go:0","msg":"real critical log"}`,
},
},
{
"file logging, json, error",
&mlog.LoggerConfiguration{
EnableConsole: false,
EnableFile: true,
FileJson: true,
FileLevel: mlog.LevelError,
},
[]string{
`{"level":"error","ts":0,"caller":"mlog/global_test.go:0","msg":"real error log"}`,
`{"level":"error","ts":0,"caller":"mlog/global_test.go:0","msg":"real critical log"}`,
},
},
{
"file logging, non-json, debug",
&mlog.LoggerConfiguration{
EnableConsole: false,
EnableFile: true,
FileJson: false,
FileLevel: mlog.LevelDebug,
},
[]string{
`TIME debug mlog/global_test.go:0 real debug log`,
`TIME info mlog/global_test.go:0 real info log`,
`TIME warn mlog/global_test.go:0 real warning log`,
`TIME error mlog/global_test.go:0 real error log`,
`TIME error mlog/global_test.go:0 real critical log`,
},
},
{
"file logging, non-json, error",
&mlog.LoggerConfiguration{
EnableConsole: false,
EnableFile: true,
FileJson: false,
FileLevel: mlog.LevelError,
},
[]string{
`TIME error mlog/global_test.go:0 real error log`,
`TIME error mlog/global_test.go:0 real critical log`,
},
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
var filePath string
if testCase.LoggerConfiguration.EnableFile {
tempDir, err := ioutil.TempDir(os.TempDir(), "TestLoggingAfterInitialized")
require.NoError(t, err)
defer os.Remove(tempDir)
filePath = filepath.Join(tempDir, "file.log")
testCase.LoggerConfiguration.FileLocation = filePath
}
logger := mlog.NewLogger(testCase.LoggerConfiguration)
mlog.InitGlobalLogger(logger)
mlog.Debug("real debug log")
mlog.Info("real info log")
mlog.Warn("real warning log")
mlog.Error("real error log")
mlog.Critical("real critical log")
if testCase.LoggerConfiguration.EnableFile {
logs, err := ioutil.ReadFile(filePath)
require.NoError(t, err)
actual := strings.TrimSpace(string(logs))
if testCase.LoggerConfiguration.FileJson {
reTs := regexp.MustCompile(`"ts":[0-9\.]+`)
reCaller := regexp.MustCompile(`"caller":"([^"]+):[0-9\.]+"`)
actual = reTs.ReplaceAllString(actual, `"ts":0`)
actual = reCaller.ReplaceAllString(actual, `"caller":"$1:0"`)
} else {
actualRows := strings.Split(actual, "\n")
for i, actualRow := range actualRows {
actualFields := strings.Split(actualRow, "\t")
if len(actualFields) > 3 {
actualFields[0] = "TIME"
reCaller := regexp.MustCompile(`([^"]+):[0-9\.]+`)
actualFields[2] = reCaller.ReplaceAllString(actualFields[2], "$1:0")
actualRows[i] = strings.Join(actualFields, "\t")
}
}
actual = strings.Join(actualRows, "\n")
}
require.Equal(t, testCase.ExpectedLogs, strings.Split(actual, "\n"))
}
})
}
}

Просмотреть файл

@@ -63,6 +63,16 @@ func getZapLevel(level string) zapcore.Level {
} }
} }
func makeEncoder(json bool) zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
if json {
return zapcore.NewJSONEncoder(encoderConfig)
}
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}
func NewLogger(config *LoggerConfiguration) *Logger { func NewLogger(config *LoggerConfiguration) *Logger {
cores := []zapcore.Core{} cores := []zapcore.Core{}
logger := &Logger{ logger := &Logger{
@@ -70,18 +80,9 @@ func NewLogger(config *LoggerConfiguration) *Logger {
fileLevel: zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)), fileLevel: zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)),
} }
encoderConfig := zap.NewProductionEncoderConfig()
var encoder zapcore.Encoder
if config.ConsoleJson {
encoder = zapcore.NewJSONEncoder(encoderConfig)
} else {
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoder = zapcore.NewConsoleEncoder(encoderConfig)
}
if config.EnableConsole { if config.EnableConsole {
writer := zapcore.Lock(os.Stdout) writer := zapcore.Lock(os.Stdout)
core := zapcore.NewCore(encoder, writer, logger.consoleLevel) core := zapcore.NewCore(makeEncoder(config.ConsoleJson), writer, logger.consoleLevel)
cores = append(cores, core) cores = append(cores, core)
} }
@@ -91,7 +92,7 @@ func NewLogger(config *LoggerConfiguration) *Logger {
MaxSize: 100, MaxSize: 100,
Compress: true, Compress: true,
}) })
core := zapcore.NewCore(encoder, writer, logger.fileLevel) core := zapcore.NewCore(makeEncoder(config.FileJson), writer, logger.fileLevel)
cores = append(cores, core) cores = append(cores, core)
} }

Просмотреть файл

@@ -36,4 +36,37 @@ type Hooks interface {
// ExecuteCommand executes a command that has been previously registered via the RegisterCommand // ExecuteCommand executes a command that has been previously registered via the RegisterCommand
// API. // API.
ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError)
// MessageWillBePosted is invoked when a message is posted by a user before it is commited
// to the database. If you also want to act on edited posts, see MessageWillBeUpdated.
// Return values should be the modified post or nil if rejected and an explanation for the user.
//
// If you don't need to modify or reject posts, use MessageHasBeenPosted instead.
//
// Note that this method will be called for posts created by plugins, including the plugin that
// created the post.
MessageWillBePosted(post *model.Post) (*model.Post, string)
// MessageWillBeUpdated is invoked when a message is updated by a user before it is commited
// to the database. If you also want to act on new posts, see MessageWillBePosted.
// Return values should be the modified post or nil if rejected and an explanation for the user.
// On rejection, the post will be kept in its previous state.
//
// If you don't need to modify or rejected updated posts, use MessageHasBeenUpdated instead.
//
// Note that this method will be called for posts updated by plugins, including the plugin that
// updated the post.
MessageWillBeUpdated(newPost, oldPost *model.Post) (*model.Post, string)
// MessageHasBeenPosted is invoked after the message has been commited to the databse.
// If you need to modify or reject the post, see MessageWillBePosted
// Note that this method will be called for posts created by plugins, including the plugin that
// created the post.
MessageHasBeenPosted(post *model.Post)
// MessageHasBeenUpdated is invoked after a message is updated and has been updated in the databse.
// If you need to modify or reject the post, see MessageWillBeUpdated
// Note that this method will be called for posts created by plugins, including the plugin that
// created the post.
MessageHasBeenUpdated(newPost, oldPost *model.Post)
} }

Просмотреть файл

@@ -306,6 +306,65 @@ func (h *MultiPluginHooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r) http.NotFound(w, r)
} }
// MessageWillBePosted invokes the MessageWillBePosted hook for all plugins. Ordering
// is not guaranteed and the next plugin will get the previous one's modifications.
// if a plugin rejects a post, the rest of the plugins will not know that an attempt was made.
// Returns the final result post, or nil if the post was rejected and a string with a reason
// for the user the message was rejected.
func (h *MultiPluginHooks) MessageWillBePosted(post *model.Post) (*model.Post, string) {
h.env.mutex.RLock()
defer h.env.mutex.RUnlock()
for _, activePlugin := range h.env.activePlugins {
if activePlugin.Supervisor == nil {
continue
}
var rejectionReason string
post, rejectionReason = activePlugin.Supervisor.Hooks().MessageWillBePosted(post)
if post == nil {
return nil, rejectionReason
}
}
return post, ""
}
// MessageWillBeUpdated invokes the MessageWillBeUpdated hook for all plugins. Ordering
// is not guaranteed and the next plugin will get the previous one's modifications.
// if a plugin rejects a post, the rest of the plugins will not know that an attempt was made.
// Returns the final result post, or nil if the post was rejected and a string with a reason
// for the user the message was rejected.
func (h *MultiPluginHooks) MessageWillBeUpdated(newPost, oldPost *model.Post) (*model.Post, string) {
h.env.mutex.RLock()
defer h.env.mutex.RUnlock()
post := newPost
for _, activePlugin := range h.env.activePlugins {
if activePlugin.Supervisor == nil {
continue
}
var rejectionReason string
post, rejectionReason = activePlugin.Supervisor.Hooks().MessageWillBeUpdated(post, oldPost)
if post == nil {
return nil, rejectionReason
}
}
return post, ""
}
func (h *MultiPluginHooks) MessageHasBeenPosted(post *model.Post) {
h.invoke(func(hooks plugin.Hooks) error {
hooks.MessageHasBeenPosted(post)
return nil
})
}
func (h *MultiPluginHooks) MessageHasBeenUpdated(newPost, oldPost *model.Post) {
h.invoke(func(hooks plugin.Hooks) error {
hooks.MessageHasBeenUpdated(newPost, oldPost)
return nil
})
}
func (h *SinglePluginHooks) invoke(f func(plugin.Hooks) error) error { func (h *SinglePluginHooks) invoke(f func(plugin.Hooks) error) error {
h.env.mutex.RLock() h.env.mutex.RLock()
defer h.env.mutex.RUnlock() defer h.env.mutex.RUnlock()

Просмотреть файл

@@ -1,344 +1,702 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Code generated by mockery v1.0.0. DO NOT EDIT.
// See License.txt for license information.
// Regenerate this file using `make plugin-mocks`.
package plugintest package plugintest
import ( import mock "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/mock" import model "github.com/mattermost/mattermost-server/model"
import plugin "github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/model" // APIMOCKINTERNAL is an autogenerated mock type for the APIMOCKINTERNAL type
"github.com/mattermost/mattermost-server/plugin" type APIMOCKINTERNAL struct {
)
type API struct {
mock.Mock
Store *KeyValueStore
}
type KeyValueStore struct {
mock.Mock mock.Mock
} }
var _ plugin.API = (*API)(nil) // AddChannelMember provides a mock function with given fields: channelId, userId
var _ plugin.KeyValueStore = (*KeyValueStore)(nil) func (_m *APIMOCKINTERNAL) AddChannelMember(channelId string, userId string) (*model.ChannelMember, *model.AppError) {
ret := _m.Called(channelId, userId)
func (m *API) LoadPluginConfiguration(dest interface{}) error { var r0 *model.ChannelMember
ret := m.Called(dest) if rf, ok := ret.Get(0).(func(string, string) *model.ChannelMember); ok {
if f, ok := ret.Get(0).(func(interface{}) error); ok { r0 = rf(channelId, userId)
return f(dest) } else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelMember)
}
} }
return ret.Error(0)
}
func (m *API) RegisterCommand(command *model.Command) error { var r1 *model.AppError
ret := m.Called(command) if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(*model.Command) error); ok { r1 = rf(channelId, userId)
return f(command) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
return ret.Error(0)
return r0, r1
} }
func (m *API) UnregisterCommand(teamId, trigger string) error { // CreateChannel provides a mock function with given fields: channel
ret := m.Called(teamId, trigger) func (_m *APIMOCKINTERNAL) CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
if f, ok := ret.Get(0).(func(string, string) error); ok { ret := _m.Called(channel)
return f(teamId, trigger)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(*model.Channel) *model.Channel); ok {
r0 = rf(channel)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
} }
return ret.Error(0)
}
func (m *API) CreateUser(user *model.User) (*model.User, *model.AppError) { var r1 *model.AppError
ret := m.Called(user) if rf, ok := ret.Get(1).(func(*model.Channel) *model.AppError); ok {
if f, ok := ret.Get(0).(func(*model.User) (*model.User, *model.AppError)); ok { r1 = rf(channel)
return f(user) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
userOut, _ := ret.Get(0).(*model.User)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return userOut, err
} }
func (m *API) DeleteUser(userId string) *model.AppError { // CreatePost provides a mock function with given fields: post
ret := m.Called(userId) func (_m *APIMOCKINTERNAL) CreatePost(post *model.Post) (*model.Post, *model.AppError) {
if f, ok := ret.Get(0).(func(string) *model.AppError); ok { ret := _m.Called(post)
return f(userId)
var r0 *model.Post
if rf, ok := ret.Get(0).(func(*model.Post) *model.Post); ok {
r0 = rf(post)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err
}
func (m *API) GetUser(userId string) (*model.User, *model.AppError) { var r1 *model.AppError
ret := m.Called(userId) if rf, ok := ret.Get(1).(func(*model.Post) *model.AppError); ok {
if f, ok := ret.Get(0).(func(string) (*model.User, *model.AppError)); ok { r1 = rf(post)
return f(userId) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
user, _ := ret.Get(0).(*model.User)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return user, err
} }
func (m *API) GetUserByEmail(email string) (*model.User, *model.AppError) { // CreateTeam provides a mock function with given fields: team
ret := m.Called(email) func (_m *APIMOCKINTERNAL) CreateTeam(team *model.Team) (*model.Team, *model.AppError) {
if f, ok := ret.Get(0).(func(string) (*model.User, *model.AppError)); ok { ret := _m.Called(team)
return f(email)
var r0 *model.Team
if rf, ok := ret.Get(0).(func(*model.Team) *model.Team); ok {
r0 = rf(team)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Team)
}
} }
user, _ := ret.Get(0).(*model.User)
err, _ := ret.Get(1).(*model.AppError)
return user, err
}
func (m *API) GetUserByUsername(name string) (*model.User, *model.AppError) { var r1 *model.AppError
ret := m.Called(name) if rf, ok := ret.Get(1).(func(*model.Team) *model.AppError); ok {
if f, ok := ret.Get(0).(func(string) (*model.User, *model.AppError)); ok { r1 = rf(team)
return f(name) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
user, _ := ret.Get(0).(*model.User)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return user, err
} }
func (m *API) UpdateUser(user *model.User) (*model.User, *model.AppError) { // CreateUser provides a mock function with given fields: user
ret := m.Called(user) func (_m *APIMOCKINTERNAL) CreateUser(user *model.User) (*model.User, *model.AppError) {
if f, ok := ret.Get(0).(func(*model.User) (*model.User, *model.AppError)); ok { ret := _m.Called(user)
return f(user)
var r0 *model.User
if rf, ok := ret.Get(0).(func(*model.User) *model.User); ok {
r0 = rf(user)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
} }
userOut, _ := ret.Get(0).(*model.User)
err, _ := ret.Get(1).(*model.AppError)
return userOut, err
}
func (m *API) CreateTeam(team *model.Team) (*model.Team, *model.AppError) { var r1 *model.AppError
ret := m.Called(team) if rf, ok := ret.Get(1).(func(*model.User) *model.AppError); ok {
if f, ok := ret.Get(0).(func(*model.Team) (*model.Team, *model.AppError)); ok { r1 = rf(user)
return f(team) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
teamOut, _ := ret.Get(0).(*model.Team)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return teamOut, err
} }
func (m *API) DeleteTeam(teamId string) *model.AppError { // DeleteChannel provides a mock function with given fields: channelId
ret := m.Called(teamId) func (_m *APIMOCKINTERNAL) DeleteChannel(channelId string) *model.AppError {
if f, ok := ret.Get(0).(func(string) *model.AppError); ok { ret := _m.Called(channelId)
return f(teamId)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(channelId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err return r0
} }
func (m *API) GetTeam(teamId string) (*model.Team, *model.AppError) { // DeleteChannelMember provides a mock function with given fields: channelId, userId
ret := m.Called(teamId) func (_m *APIMOCKINTERNAL) DeleteChannelMember(channelId string, userId string) *model.AppError {
if f, ok := ret.Get(0).(func(string) (*model.Team, *model.AppError)); ok { ret := _m.Called(channelId, userId)
return f(teamId)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string, string) *model.AppError); ok {
r0 = rf(channelId, userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
} }
team, _ := ret.Get(0).(*model.Team)
err, _ := ret.Get(1).(*model.AppError) return r0
return team, err
} }
func (m *API) GetTeamByName(name string) (*model.Team, *model.AppError) { // DeletePost provides a mock function with given fields: postId
ret := m.Called(name) func (_m *APIMOCKINTERNAL) DeletePost(postId string) *model.AppError {
if f, ok := ret.Get(0).(func(string) (*model.Team, *model.AppError)); ok { ret := _m.Called(postId)
return f(name)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(postId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
} }
team, _ := ret.Get(0).(*model.Team)
err, _ := ret.Get(1).(*model.AppError) return r0
return team, err
} }
func (m *API) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { // DeleteTeam provides a mock function with given fields: teamId
ret := m.Called(team) func (_m *APIMOCKINTERNAL) DeleteTeam(teamId string) *model.AppError {
if f, ok := ret.Get(0).(func(*model.Team) (*model.Team, *model.AppError)); ok { ret := _m.Called(teamId)
return f(team)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(teamId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
} }
teamOut, _ := ret.Get(0).(*model.Team)
err, _ := ret.Get(1).(*model.AppError) return r0
return teamOut, err
} }
func (m *API) CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) { // DeleteUser provides a mock function with given fields: userId
ret := m.Called(channel) func (_m *APIMOCKINTERNAL) DeleteUser(userId string) *model.AppError {
if f, ok := ret.Get(0).(func(*model.Channel) (*model.Channel, *model.AppError)); ok { ret := _m.Called(userId)
return f(channel)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
} }
channelOut, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError) return r0
return channelOut, err
} }
func (m *API) DeleteChannel(channelId string) *model.AppError { // GetChannel provides a mock function with given fields: channelId
ret := m.Called(channelId) func (_m *APIMOCKINTERNAL) GetChannel(channelId string) (*model.Channel, *model.AppError) {
if f, ok := ret.Get(0).(func(string) *model.AppError); ok { ret := _m.Called(channelId)
return f(channelId)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(string) *model.Channel); ok {
r0 = rf(channelId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err
}
func (m *API) GetChannel(channelId string) (*model.Channel, *model.AppError) { var r1 *model.AppError
ret := m.Called(channelId) if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(string) (*model.Channel, *model.AppError)); ok { r1 = rf(channelId)
return f(channelId) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
channel, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return channel, err
} }
func (m *API) GetChannelByName(name, teamId string) (*model.Channel, *model.AppError) { // GetChannelByName provides a mock function with given fields: name, teamId
ret := m.Called(name, teamId) func (_m *APIMOCKINTERNAL) GetChannelByName(name string, teamId string) (*model.Channel, *model.AppError) {
if f, ok := ret.Get(0).(func(_, _ string) (*model.Channel, *model.AppError)); ok { ret := _m.Called(name, teamId)
return f(name, teamId)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(string, string) *model.Channel); ok {
r0 = rf(name, teamId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
} }
channel, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError)
return channel, err
}
func (m *API) GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError) { var r1 *model.AppError
ret := m.Called(userId1, userId2) if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(_, _ string) (*model.Channel, *model.AppError)); ok { r1 = rf(name, teamId)
return f(userId1, userId2) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
channel, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return channel, err
} }
func (m *API) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) { // GetChannelMember provides a mock function with given fields: channelId, userId
ret := m.Called(userIds) func (_m *APIMOCKINTERNAL) GetChannelMember(channelId string, userId string) (*model.ChannelMember, *model.AppError) {
if f, ok := ret.Get(0).(func([]string) (*model.Channel, *model.AppError)); ok { ret := _m.Called(channelId, userId)
return f(userIds)
var r0 *model.ChannelMember
if rf, ok := ret.Get(0).(func(string, string) *model.ChannelMember); ok {
r0 = rf(channelId, userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelMember)
}
} }
channel, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError)
return channel, err
}
func (m *API) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) { var r1 *model.AppError
ret := m.Called(channel) if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(*model.Channel) (*model.Channel, *model.AppError)); ok { r1 = rf(channelId, userId)
return f(channel) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
channelOut, _ := ret.Get(0).(*model.Channel)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return channelOut, err
} }
func (m *API) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { // GetDirectChannel provides a mock function with given fields: userId1, userId2
ret := m.Called(channelId, userId) func (_m *APIMOCKINTERNAL) GetDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) {
if f, ok := ret.Get(0).(func(_, _ string) (*model.ChannelMember, *model.AppError)); ok { ret := _m.Called(userId1, userId2)
return f(channelId, userId)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(string, string) *model.Channel); ok {
r0 = rf(userId1, userId2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
} }
member, _ := ret.Get(0).(*model.ChannelMember)
err, _ := ret.Get(1).(*model.AppError)
return member, err
}
func (m *API) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { var r1 *model.AppError
ret := m.Called(channelId, userId) if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(_, _ string) (*model.ChannelMember, *model.AppError)); ok { r1 = rf(userId1, userId2)
return f(channelId, userId) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
member, _ := ret.Get(0).(*model.ChannelMember)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return member, err
} }
func (m *API) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) { // GetGroupChannel provides a mock function with given fields: userIds
ret := m.Called(channelId, userId, newRoles) func (_m *APIMOCKINTERNAL) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) {
if f, ok := ret.Get(0).(func(_, _, _ string) (*model.ChannelMember, *model.AppError)); ok { ret := _m.Called(userIds)
return f(channelId, userId, newRoles)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func([]string) *model.Channel); ok {
r0 = rf(userIds)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
} }
member, _ := ret.Get(0).(*model.ChannelMember)
err, _ := ret.Get(1).(*model.AppError)
return member, err
}
func (m *API) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) { var r1 *model.AppError
ret := m.Called(channelId, userId, notifications) if rf, ok := ret.Get(1).(func([]string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(_, _ string, _ map[string]string) (*model.ChannelMember, *model.AppError)); ok { r1 = rf(userIds)
return f(channelId, userId, notifications) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
member, _ := ret.Get(0).(*model.ChannelMember)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return member, err
} }
func (m *API) DeleteChannelMember(channelId, userId string) *model.AppError { // GetPost provides a mock function with given fields: postId
ret := m.Called(channelId, userId) func (_m *APIMOCKINTERNAL) GetPost(postId string) (*model.Post, *model.AppError) {
if f, ok := ret.Get(0).(func(_, _ string) *model.AppError); ok { ret := _m.Called(postId)
return f(channelId, userId)
var r0 *model.Post
if rf, ok := ret.Get(0).(func(string) *model.Post); ok {
r0 = rf(postId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err
}
func (m *API) CreatePost(post *model.Post) (*model.Post, *model.AppError) { var r1 *model.AppError
ret := m.Called(post) if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(*model.Post) (*model.Post, *model.AppError)); ok { r1 = rf(postId)
return f(post) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
postOut, _ := ret.Get(0).(*model.Post)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return postOut, err
} }
func (m *API) DeletePost(postId string) *model.AppError { // GetTeam provides a mock function with given fields: teamId
ret := m.Called(postId) func (_m *APIMOCKINTERNAL) GetTeam(teamId string) (*model.Team, *model.AppError) {
if f, ok := ret.Get(0).(func(string) *model.AppError); ok { ret := _m.Called(teamId)
return f(postId)
var r0 *model.Team
if rf, ok := ret.Get(0).(func(string) *model.Team); ok {
r0 = rf(teamId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Team)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err
}
func (m *API) GetPost(postId string) (*model.Post, *model.AppError) { var r1 *model.AppError
ret := m.Called(postId) if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
if f, ok := ret.Get(0).(func(string) (*model.Post, *model.AppError)); ok { r1 = rf(teamId)
return f(postId) } else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
} }
post, _ := ret.Get(0).(*model.Post)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return post, err
} }
func (m *API) UpdatePost(post *model.Post) (*model.Post, *model.AppError) { // GetTeamByName provides a mock function with given fields: name
ret := m.Called(post) func (_m *APIMOCKINTERNAL) GetTeamByName(name string) (*model.Team, *model.AppError) {
if f, ok := ret.Get(0).(func(*model.Post) (*model.Post, *model.AppError)); ok { ret := _m.Called(name)
return f(post)
var r0 *model.Team
if rf, ok := ret.Get(0).(func(string) *model.Team); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Team)
}
} }
postOut, _ := ret.Get(0).(*model.Post)
err, _ := ret.Get(1).(*model.AppError)
return postOut, err
}
func (m *API) KeyValueStore() plugin.KeyValueStore { var r1 *model.AppError
return m.Store if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
} r1 = rf(name)
} else {
func (m *KeyValueStore) Set(key string, value []byte) *model.AppError { if ret.Get(1) != nil {
ret := m.Called(key, value) r1 = ret.Get(1).(*model.AppError)
if f, ok := ret.Get(0).(func(string, []byte) *model.AppError); ok { }
return f(key, value)
} }
err, _ := ret.Get(0).(*model.AppError)
return err return r0, r1
} }
func (m *KeyValueStore) Get(key string) ([]byte, *model.AppError) { // GetUser provides a mock function with given fields: userId
ret := m.Called(key) func (_m *APIMOCKINTERNAL) GetUser(userId string) (*model.User, *model.AppError) {
if f, ok := ret.Get(0).(func(string) ([]byte, *model.AppError)); ok { ret := _m.Called(userId)
return f(key)
var r0 *model.User
if rf, ok := ret.Get(0).(func(string) *model.User); ok {
r0 = rf(userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
} }
psv, _ := ret.Get(0).([]byte)
err, _ := ret.Get(1).(*model.AppError) var r1 *model.AppError
return psv, err if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
r1 = rf(userId)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
} }
func (m *KeyValueStore) Delete(key string) *model.AppError { // GetUserByEmail provides a mock function with given fields: email
ret := m.Called(key) func (_m *APIMOCKINTERNAL) GetUserByEmail(email string) (*model.User, *model.AppError) {
if f, ok := ret.Get(0).(func(string) *model.AppError); ok { ret := _m.Called(email)
return f(key)
var r0 *model.User
if rf, ok := ret.Get(0).(func(string) *model.User); ok {
r0 = rf(email)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
} }
err, _ := ret.Get(0).(*model.AppError)
return err var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
r1 = rf(email)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetUserByUsername provides a mock function with given fields: name
func (_m *APIMOCKINTERNAL) GetUserByUsername(name string) (*model.User, *model.AppError) {
ret := _m.Called(name)
var r0 *model.User
if rf, ok := ret.Get(0).(func(string) *model.User); ok {
r0 = rf(name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
r1 = rf(name)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// KeyValueStore provides a mock function with given fields:
func (_m *APIMOCKINTERNAL) KeyValueStore() plugin.KeyValueStore {
ret := _m.Called()
var r0 plugin.KeyValueStore
if rf, ok := ret.Get(0).(func() plugin.KeyValueStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(plugin.KeyValueStore)
}
}
return r0
}
// LoadPluginConfiguration provides a mock function with given fields: dest
func (_m *APIMOCKINTERNAL) LoadPluginConfiguration(dest interface{}) error {
ret := _m.Called(dest)
var r0 error
if rf, ok := ret.Get(0).(func(interface{}) error); ok {
r0 = rf(dest)
} else {
r0 = ret.Error(0)
}
return r0
}
// RegisterCommand provides a mock function with given fields: command
func (_m *APIMOCKINTERNAL) RegisterCommand(command *model.Command) error {
ret := _m.Called(command)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Command) error); ok {
r0 = rf(command)
} else {
r0 = ret.Error(0)
}
return r0
}
// UnregisterCommand provides a mock function with given fields: teamId, trigger
func (_m *APIMOCKINTERNAL) UnregisterCommand(teamId string, trigger string) error {
ret := _m.Called(teamId, trigger)
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(teamId, trigger)
} else {
r0 = ret.Error(0)
}
return r0
}
// UpdateChannel provides a mock function with given fields: channel
func (_m *APIMOCKINTERNAL) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
ret := _m.Called(channel)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(*model.Channel) *model.Channel); ok {
r0 = rf(channel)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(*model.Channel) *model.AppError); ok {
r1 = rf(channel)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// UpdateChannelMemberNotifications provides a mock function with given fields: channelId, userId, notifications
func (_m *APIMOCKINTERNAL) UpdateChannelMemberNotifications(channelId string, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) {
ret := _m.Called(channelId, userId, notifications)
var r0 *model.ChannelMember
if rf, ok := ret.Get(0).(func(string, string, map[string]string) *model.ChannelMember); ok {
r0 = rf(channelId, userId, notifications)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelMember)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, map[string]string) *model.AppError); ok {
r1 = rf(channelId, userId, notifications)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// UpdateChannelMemberRoles provides a mock function with given fields: channelId, userId, newRoles
func (_m *APIMOCKINTERNAL) UpdateChannelMemberRoles(channelId string, userId string, newRoles string) (*model.ChannelMember, *model.AppError) {
ret := _m.Called(channelId, userId, newRoles)
var r0 *model.ChannelMember
if rf, ok := ret.Get(0).(func(string, string, string) *model.ChannelMember); ok {
r0 = rf(channelId, userId, newRoles)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelMember)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
r1 = rf(channelId, userId, newRoles)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// UpdatePost provides a mock function with given fields: post
func (_m *APIMOCKINTERNAL) UpdatePost(post *model.Post) (*model.Post, *model.AppError) {
ret := _m.Called(post)
var r0 *model.Post
if rf, ok := ret.Get(0).(func(*model.Post) *model.Post); ok {
r0 = rf(post)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(*model.Post) *model.AppError); ok {
r1 = rf(post)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// UpdateTeam provides a mock function with given fields: team
func (_m *APIMOCKINTERNAL) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
ret := _m.Called(team)
var r0 *model.Team
if rf, ok := ret.Get(0).(func(*model.Team) *model.Team); ok {
r0 = rf(team)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Team)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(*model.Team) *model.AppError); ok {
r1 = rf(team)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// UpdateUser provides a mock function with given fields: user
func (_m *APIMOCKINTERNAL) UpdateUser(user *model.User) (*model.User, *model.AppError) {
ret := _m.Called(user)
var r0 *model.User
if rf, ok := ret.Get(0).(func(*model.User) *model.User); ok {
r0 = rf(user)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(*model.User) *model.AppError); ok {
r1 = rf(user)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
} }

18
plugin/plugintest/apioverride.go Обычный файл
Просмотреть файл

@@ -0,0 +1,18 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package plugintest
import "github.com/mattermost/mattermost-server/plugin"
type API struct {
APIMOCKINTERNAL
Store *KeyValueStore
}
var _ plugin.API = (*API)(nil)
var _ plugin.KeyValueStore = (*KeyValueStore)(nil)
func (m *API) KeyValueStore() plugin.KeyValueStore {
return m.Store
}

Просмотреть файл

@@ -1,49 +1,143 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Code generated by mockery v1.0.0. DO NOT EDIT.
// See License.txt for license information.
// Regenerate this file using `make plugin-mocks`.
package plugintest package plugintest
import ( import http "net/http"
"net/http" import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
"github.com/stretchr/testify/mock" import plugin "github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
)
// Hooks is an autogenerated mock type for the Hooks type
type Hooks struct { type Hooks struct {
mock.Mock mock.Mock
} }
var _ plugin.Hooks = (*Hooks)(nil) // ExecuteCommand provides a mock function with given fields: args
func (_m *Hooks) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
ret := _m.Called(args)
func (m *Hooks) OnActivate(api plugin.API) error { var r0 *model.CommandResponse
ret := m.Called(api) if rf, ok := ret.Get(0).(func(*model.CommandArgs) *model.CommandResponse); ok {
if f, ok := ret.Get(0).(func(plugin.API) error); ok { r0 = rf(args)
return f(api) } else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.CommandResponse)
}
} }
return ret.Error(0)
}
func (m *Hooks) OnDeactivate() error { var r1 *model.AppError
return m.Called().Error(0) if rf, ok := ret.Get(1).(func(*model.CommandArgs) *model.AppError); ok {
} r1 = rf(args)
} else {
func (m *Hooks) OnConfigurationChange() error { if ret.Get(1) != nil {
return m.Called().Error(0) r1 = ret.Get(1).(*model.AppError)
} }
func (m *Hooks) ServeHTTP(w http.ResponseWriter, r *http.Request) {
m.Called(w, r)
}
func (m *Hooks) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
ret := m.Called(args)
if f, ok := ret.Get(0).(func(*model.CommandArgs) (*model.CommandResponse, *model.AppError)); ok {
return f(args)
} }
resp, _ := ret.Get(0).(*model.CommandResponse)
err, _ := ret.Get(1).(*model.AppError) return r0, r1
return resp, err }
// MessageHasBeenPosted provides a mock function with given fields: post
func (_m *Hooks) MessageHasBeenPosted(post *model.Post) {
_m.Called(post)
}
// MessageHasBeenUpdated provides a mock function with given fields: newPost, oldPost
func (_m *Hooks) MessageHasBeenUpdated(newPost *model.Post, oldPost *model.Post) {
_m.Called(newPost, oldPost)
}
// MessageWillBePosted provides a mock function with given fields: post
func (_m *Hooks) MessageWillBePosted(post *model.Post) (*model.Post, string) {
ret := _m.Called(post)
var r0 *model.Post
if rf, ok := ret.Get(0).(func(*model.Post) *model.Post); ok {
r0 = rf(post)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post)
}
}
var r1 string
if rf, ok := ret.Get(1).(func(*model.Post) string); ok {
r1 = rf(post)
} else {
r1 = ret.Get(1).(string)
}
return r0, r1
}
// MessageWillBeUpdated provides a mock function with given fields: newPost, oldPost
func (_m *Hooks) MessageWillBeUpdated(newPost *model.Post, oldPost *model.Post) (*model.Post, string) {
ret := _m.Called(newPost, oldPost)
var r0 *model.Post
if rf, ok := ret.Get(0).(func(*model.Post, *model.Post) *model.Post); ok {
r0 = rf(newPost, oldPost)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post)
}
}
var r1 string
if rf, ok := ret.Get(1).(func(*model.Post, *model.Post) string); ok {
r1 = rf(newPost, oldPost)
} else {
r1 = ret.Get(1).(string)
}
return r0, r1
}
// OnActivate provides a mock function with given fields: _a0
func (_m *Hooks) OnActivate(_a0 plugin.API) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(plugin.API) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// OnConfigurationChange provides a mock function with given fields:
func (_m *Hooks) OnConfigurationChange() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// OnDeactivate provides a mock function with given fields:
func (_m *Hooks) OnDeactivate() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// ServeHTTP provides a mock function with given fields: _a0, _a1
func (_m *Hooks) ServeHTTP(_a0 http.ResponseWriter, _a1 *http.Request) {
_m.Called(_a0, _a1)
} }

70
plugin/plugintest/key_value_store.go Обычный файл
Просмотреть файл

@@ -0,0 +1,70 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make plugin-mocks`.
package plugintest
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
// KeyValueStore is an autogenerated mock type for the KeyValueStore type
type KeyValueStore struct {
mock.Mock
}
// Delete provides a mock function with given fields: key
func (_m *KeyValueStore) Delete(key string) *model.AppError {
ret := _m.Called(key)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(key)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// Get provides a mock function with given fields: key
func (_m *KeyValueStore) Get(key string) ([]byte, *model.AppError) {
ret := _m.Called(key)
var r0 []byte
if rf, ok := ret.Get(0).(func(string) []byte); ok {
r0 = rf(key)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
r1 = rf(key)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// Set provides a mock function with given fields: key, value
func (_m *KeyValueStore) Set(key string, value []byte) *model.AppError {
ret := _m.Called(key, value)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string, []byte) *model.AppError); ok {
r0 = rf(key, value)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}

Просмотреть файл

@@ -90,10 +90,10 @@ func TestAPI(t *testing.T) {
api.On("UnregisterCommand", "team", "trigger").Return(nil).Once() api.On("UnregisterCommand", "team", "trigger").Return(nil).Once()
assert.NoError(t, remote.UnregisterCommand("team", "trigger")) assert.NoError(t, remote.UnregisterCommand("team", "trigger"))
api.On("CreateChannel", mock.AnythingOfType("*model.Channel")).Return(func(c *model.Channel) (*model.Channel, *model.AppError) { api.On("CreateChannel", mock.AnythingOfType("*model.Channel")).Return(func(c *model.Channel) *model.Channel {
c.Id = "thechannelid" c.Id = "thechannelid"
return c, nil return c
}).Once() }, nil).Once()
channel, err := remote.CreateChannel(testChannel) channel, err := remote.CreateChannel(testChannel)
assert.Equal(t, "thechannelid", channel.Id) assert.Equal(t, "thechannelid", channel.Id)
assert.Nil(t, err) assert.Nil(t, err)
@@ -121,9 +121,9 @@ func TestAPI(t *testing.T) {
assert.Equal(t, testChannel, channel) assert.Equal(t, testChannel, channel)
assert.Nil(t, err) assert.Nil(t, err)
api.On("UpdateChannel", mock.AnythingOfType("*model.Channel")).Return(func(c *model.Channel) (*model.Channel, *model.AppError) { api.On("UpdateChannel", mock.AnythingOfType("*model.Channel")).Return(func(c *model.Channel) *model.Channel {
return c, nil return c
}).Once() }, nil).Once()
channel, err = remote.UpdateChannel(testChannel) channel, err = remote.UpdateChannel(testChannel)
assert.Equal(t, testChannel, channel) assert.Equal(t, testChannel, channel)
assert.Nil(t, err) assert.Nil(t, err)
@@ -154,10 +154,10 @@ func TestAPI(t *testing.T) {
err = remote.DeleteChannelMember("thechannelid", "theuserid") err = remote.DeleteChannelMember("thechannelid", "theuserid")
assert.Nil(t, err) assert.Nil(t, err)
api.On("CreateUser", mock.AnythingOfType("*model.User")).Return(func(u *model.User) (*model.User, *model.AppError) { api.On("CreateUser", mock.AnythingOfType("*model.User")).Return(func(u *model.User) *model.User {
u.Id = "theuserid" u.Id = "theuserid"
return u, nil return u
}).Once() }, nil).Once()
user, err := remote.CreateUser(testUser) user, err := remote.CreateUser(testUser)
assert.Equal(t, "theuserid", user.Id) assert.Equal(t, "theuserid", user.Id)
assert.Nil(t, err) assert.Nil(t, err)
@@ -180,17 +180,17 @@ func TestAPI(t *testing.T) {
assert.Equal(t, testUser, user) assert.Equal(t, testUser, user)
assert.Nil(t, err) assert.Nil(t, err)
api.On("UpdateUser", mock.AnythingOfType("*model.User")).Return(func(u *model.User) (*model.User, *model.AppError) { api.On("UpdateUser", mock.AnythingOfType("*model.User")).Return(func(u *model.User) *model.User {
return u, nil return u
}).Once() }, nil).Once()
user, err = remote.UpdateUser(testUser) user, err = remote.UpdateUser(testUser)
assert.Equal(t, testUser, user) assert.Equal(t, testUser, user)
assert.Nil(t, err) assert.Nil(t, err)
api.On("CreateTeam", mock.AnythingOfType("*model.Team")).Return(func(t *model.Team) (*model.Team, *model.AppError) { api.On("CreateTeam", mock.AnythingOfType("*model.Team")).Return(func(t *model.Team) *model.Team {
t.Id = "theteamid" t.Id = "theteamid"
return t, nil return t
}).Once() }, nil).Once()
team, err := remote.CreateTeam(testTeam) team, err := remote.CreateTeam(testTeam)
assert.Equal(t, "theteamid", team.Id) assert.Equal(t, "theteamid", team.Id)
assert.Nil(t, err) assert.Nil(t, err)
@@ -213,17 +213,17 @@ func TestAPI(t *testing.T) {
assert.Nil(t, team) assert.Nil(t, team)
assert.Equal(t, teamNotFoundError, err) assert.Equal(t, teamNotFoundError, err)
api.On("UpdateTeam", mock.AnythingOfType("*model.Team")).Return(func(t *model.Team) (*model.Team, *model.AppError) { api.On("UpdateTeam", mock.AnythingOfType("*model.Team")).Return(func(t *model.Team) *model.Team {
return t, nil return t
}).Once() }, nil).Once()
team, err = remote.UpdateTeam(testTeam) team, err = remote.UpdateTeam(testTeam)
assert.Equal(t, testTeam, team) assert.Equal(t, testTeam, team)
assert.Nil(t, err) assert.Nil(t, err)
api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) (*model.Post, *model.AppError) { api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) *model.Post {
p.Id = "thepostid" p.Id = "thepostid"
return p, nil return p
}).Once() }, nil).Once()
post, err := remote.CreatePost(testPost) post, err := remote.CreatePost(testPost)
require.Nil(t, err) require.Nil(t, err)
assert.NotEmpty(t, post.Id) assert.NotEmpty(t, post.Id)
@@ -237,9 +237,9 @@ func TestAPI(t *testing.T) {
assert.Equal(t, testPost, post) assert.Equal(t, testPost, post)
assert.Nil(t, err) assert.Nil(t, err)
api.On("UpdatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) (*model.Post, *model.AppError) { api.On("UpdatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) *model.Post {
return p, nil return p
}).Once() }, nil).Once()
post, err = remote.UpdatePost(testPost) post, err = remote.UpdatePost(testPost)
assert.Equal(t, testPost, post) assert.Equal(t, testPost, post)
assert.Nil(t, err) assert.Nil(t, err)
@@ -248,9 +248,9 @@ func TestAPI(t *testing.T) {
err = remote.KeyValueStore().Set("thekey", []byte("thevalue")) err = remote.KeyValueStore().Set("thekey", []byte("thevalue"))
assert.Nil(t, err) assert.Nil(t, err)
api.KeyValueStore().(*plugintest.KeyValueStore).On("Get", "thekey").Return(func(key string) ([]byte, *model.AppError) { api.KeyValueStore().(*plugintest.KeyValueStore).On("Get", "thekey").Return(func(key string) []byte {
return []byte("thevalue"), nil return []byte("thevalue")
}).Once() }, nil).Once()
ret, err := remote.KeyValueStore().Get("thekey") ret, err := remote.KeyValueStore().Get("thekey")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, []byte("thevalue"), ret) assert.Equal(t, []byte("thevalue"), ret)
@@ -267,10 +267,10 @@ func TestAPI_GobRegistration(t *testing.T) {
defer api.AssertExpectations(t) defer api.AssertExpectations(t)
testAPIRPC(&api, func(remote plugin.API) { testAPIRPC(&api, func(remote plugin.API) {
api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) (*model.Post, *model.AppError) { api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(func(p *model.Post) *model.Post {
p.Id = "thepostid" p.Id = "thepostid"
return p, nil return p
}).Once() }, nil).Once()
_, err := remote.CreatePost(&model.Post{ _, err := remote.CreatePost(&model.Post{
Message: "hello", Message: "hello",
Props: map[string]interface{}{ Props: map[string]interface{}{

Просмотреть файл

@@ -141,6 +141,52 @@ func (h *LocalHooks) ExecuteCommand(args *model.CommandArgs, reply *HooksExecute
return nil return nil
} }
type MessageWillBeReply struct {
Post *model.Post
RejectionReason string
}
type MessageUpdatedArgs struct {
NewPost *model.Post
OldPost *model.Post
}
func (h *LocalHooks) MessageWillBePosted(args *model.Post, reply *MessageWillBeReply) error {
if hook, ok := h.hooks.(interface {
MessageWillBePosted(*model.Post) (*model.Post, string)
}); ok {
reply.Post, reply.RejectionReason = hook.MessageWillBePosted(args)
}
return nil
}
func (h *LocalHooks) MessageWillBeUpdated(args *MessageUpdatedArgs, reply *MessageWillBeReply) error {
if hook, ok := h.hooks.(interface {
MessageWillBeUpdated(*model.Post, *model.Post) (*model.Post, string)
}); ok {
reply.Post, reply.RejectionReason = hook.MessageWillBeUpdated(args.NewPost, args.OldPost)
}
return nil
}
func (h *LocalHooks) MessageHasBeenPosted(args *model.Post, reply *struct{}) error {
if hook, ok := h.hooks.(interface {
MessageHasBeenPosted(*model.Post)
}); ok {
hook.MessageHasBeenPosted(args)
}
return nil
}
func (h *LocalHooks) MessageHasBeenUpdated(args *MessageUpdatedArgs, reply *struct{}) error {
if hook, ok := h.hooks.(interface {
MessageHasBeenUpdated(*model.Post, *model.Post)
}); ok {
hook.MessageHasBeenUpdated(args.NewPost, args.OldPost)
}
return nil
}
func ServeHooks(hooks interface{}, conn io.ReadWriteCloser, muxer *Muxer) { func ServeHooks(hooks interface{}, conn io.ReadWriteCloser, muxer *Muxer) {
server := rpc.NewServer() server := rpc.NewServer()
server.Register(&LocalHooks{ server.Register(&LocalHooks{
@@ -158,6 +204,10 @@ const (
remoteServeHTTP = 2 remoteServeHTTP = 2
remoteOnConfigurationChange = 3 remoteOnConfigurationChange = 3
remoteExecuteCommand = 4 remoteExecuteCommand = 4
remoteMessageWillBePosted = 5
remoteMessageWillBeUpdated = 6
remoteMessageHasBeenPosted = 7
remoteMessageHasBeenUpdated = 8
maxRemoteHookCount = iota maxRemoteHookCount = iota
) )
@@ -255,6 +305,54 @@ func (h *RemoteHooks) ExecuteCommand(args *model.CommandArgs) (*model.CommandRes
return reply.Response, reply.Error return reply.Response, reply.Error
} }
func (h *RemoteHooks) MessageWillBePosted(args *model.Post) (*model.Post, string) {
if !h.implemented[remoteMessageWillBePosted] {
return args, ""
}
var reply MessageWillBeReply
if err := h.client.Call("LocalHooks.MessageWillBePosted", args, &reply); err != nil {
return nil, ""
}
return reply.Post, reply.RejectionReason
}
func (h *RemoteHooks) MessageWillBeUpdated(newPost, oldPost *model.Post) (*model.Post, string) {
if !h.implemented[remoteMessageWillBeUpdated] {
return newPost, ""
}
var reply MessageWillBeReply
args := &MessageUpdatedArgs{
NewPost: newPost,
OldPost: oldPost,
}
if err := h.client.Call("LocalHooks.MessageWillBeUpdated", args, &reply); err != nil {
return nil, ""
}
return reply.Post, reply.RejectionReason
}
func (h *RemoteHooks) MessageHasBeenPosted(args *model.Post) {
if !h.implemented[remoteMessageHasBeenPosted] {
return
}
if err := h.client.Call("LocalHooks.MessageHasBeenPosted", args, nil); err != nil {
return
}
}
func (h *RemoteHooks) MessageHasBeenUpdated(newPost, oldPost *model.Post) {
if !h.implemented[remoteMessageHasBeenUpdated] {
return
}
args := &MessageUpdatedArgs{
NewPost: newPost,
OldPost: oldPost,
}
if err := h.client.Call("LocalHooks.MessageHasBeenUpdated", args, nil); err != nil {
return
}
}
func (h *RemoteHooks) Close() error { func (h *RemoteHooks) Close() error {
if h.apiCloser != nil { if h.apiCloser != nil {
h.apiCloser.Close() h.apiCloser.Close()
@@ -286,6 +384,14 @@ func ConnectHooks(conn io.ReadWriteCloser, muxer *Muxer, pluginId string) (*Remo
remote.implemented[remoteServeHTTP] = true remote.implemented[remoteServeHTTP] = true
case "ExecuteCommand": case "ExecuteCommand":
remote.implemented[remoteExecuteCommand] = true remote.implemented[remoteExecuteCommand] = true
case "MessageWillBePosted":
remote.implemented[remoteMessageWillBePosted] = true
case "MessageWillBeUpdated":
remote.implemented[remoteMessageWillBeUpdated] = true
case "MessageHasBeenPosted":
remote.implemented[remoteMessageHasBeenPosted] = true
case "MessageHasBeenUpdated":
remote.implemented[remoteMessageHasBeenUpdated] = true
} }
} }
return remote, nil return remote, nil

Просмотреть файл

@@ -91,6 +91,30 @@ func TestHooks(t *testing.T) {
}) })
assert.Equal(t, "bar", commandResponse.Text) assert.Equal(t, "bar", commandResponse.Text)
assert.Nil(t, appErr) assert.Nil(t, appErr)
hooks.On("MessageWillBePosted", mock.AnythingOfType("*model.Post")).Return(func(post *model.Post) *model.Post {
post.Message += "_testing"
return post
}, "changemessage")
post, changemessage := remote.MessageWillBePosted(&model.Post{Id: "1", Message: "base"})
assert.Equal(t, "changemessage", changemessage)
assert.Equal(t, "base_testing", post.Message)
assert.Equal(t, "1", post.Id)
hooks.On("MessageWillBeUpdated", mock.AnythingOfType("*model.Post"), mock.AnythingOfType("*model.Post")).Return(func(newPost, oldPost *model.Post) *model.Post {
newPost.Message += "_testing"
return newPost
}, "changemessage2")
post2, changemessage2 := remote.MessageWillBeUpdated(&model.Post{Id: "2", Message: "base2"}, &model.Post{Id: "OLD", Message: "OLDMESSAGE"})
assert.Equal(t, "changemessage2", changemessage2)
assert.Equal(t, "base2_testing", post2.Message)
assert.Equal(t, "2", post2.Id)
hooks.On("MessageHasBeenPosted", mock.AnythingOfType("*model.Post")).Return(nil)
remote.MessageHasBeenPosted(&model.Post{})
hooks.On("MessageHasBeenUpdated", mock.AnythingOfType("*model.Post"), mock.AnythingOfType("*model.Post")).Return(nil)
remote.MessageHasBeenUpdated(&model.Post{}, &model.Post{})
})) }))
} }

Просмотреть файл

@@ -5,7 +5,7 @@ count=0
for fileType in GoFiles; do for fileType in GoFiles; do
for file in `go list -f $'{{range .GoFiles}}{{$.Dir}}/{{.}}\n{{end}}' "$@"`; do for file in `go list -f $'{{range .GoFiles}}{{$.Dir}}/{{.}}\n{{end}}' "$@"`; do
case $file in case $file in
*/utils/lru.go|*/store/storetest/mocks/*|*/app/plugin/jira/plugin_*|*/app/plugin/zoom/plugin_*) */utils/lru.go|*/store/storetest/mocks/*|*/app/plugin/jira/plugin_*|*/plugin/plugintest/*|*/app/plugin/zoom/plugin_*)
# Third-party, doesn't require a header. # Third-party, doesn't require a header.
;; ;;
*) *)

Просмотреть файл

@@ -49,10 +49,9 @@ func (c *Context) LogAuditWithUserId(userId, extraInfo string) {
} }
func (c *Context) LogError(err *model.AppError) { func (c *Context) LogError(err *model.AppError) {
// Filter out 404s, endless reconnects and browser compatibility errors // Filter out 404s, endless reconnects and browser compatibility errors
if err.StatusCode == http.StatusNotFound || if err.StatusCode == http.StatusNotFound ||
(c.Path == "/api/v3/users/websocket" && err.StatusCode == 401) || (c.Path == "/api/v3/users/websocket" && err.StatusCode == http.StatusUnauthorized) ||
err.Id == "web.check_browser_compatibility.app_error" { err.Id == "web.check_browser_compatibility.app_error" {
c.LogDebug(err) c.LogDebug(err)
} else { } else {
@@ -62,8 +61,13 @@ func (c *Context) LogError(err *model.AppError) {
} }
func (c *Context) LogInfo(err *model.AppError) { func (c *Context) LogInfo(err *model.AppError) {
mlog.Info(fmt.Sprintf("%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]", c.Path, err.Where, err.StatusCode, // Filter out 401s
c.RequestId, c.Session.UserId, c.IpAddress, err.SystemMessage(utils.TDefault), err.DetailedError), mlog.String("user_id", c.Session.UserId)) if err.StatusCode == http.StatusUnauthorized {
c.LogDebug(err)
} else {
mlog.Info(fmt.Sprintf("%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]", c.Path, err.Where, err.StatusCode,
c.RequestId, c.Session.UserId, c.IpAddress, err.SystemMessage(utils.TDefault), err.DetailedError), mlog.String("user_id", c.Session.UserId))
}
} }
func (c *Context) LogDebug(err *model.AppError) { func (c *Context) LogDebug(err *model.AppError) {