From 7b2861de3a09cf00d00b0872cc537d54302c4bfa Mon Sep 17 00:00:00 2001 From: Jonathan Fritz Date: Mon, 12 Feb 2018 16:14:52 -0500 Subject: Removed unused fields from ChannelMemberHistory table, introduced new model.ChannelMemberHistoryResult object that includes those fields that are selected from a join on other tables --- app/channel_test.go | 20 +++++++++--------- model/ChannelMemberHistoryResult.go | 15 +++++++++++++ model/channel_member_history.go | 4 ---- store/sqlstore/channel_member_history_store.go | 8 +++---- store/sqlstore/upgrade.go | 2 ++ store/storetest/channel_member_history_store.go | 28 ++++++++++++------------- 6 files changed, 45 insertions(+), 32 deletions(-) create mode 100644 model/ChannelMemberHistoryResult.go diff --git a/app/channel_test.go b/app/channel_test.go index d315fbae6..e4a0e4320 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -116,14 +116,14 @@ func TestJoinDefaultChannelsTownSquare(t *testing.T) { // figure out the initial number of users in town square townSquareChannelId := store.Must(th.App.Srv.Store.Channel().GetByName(th.BasicTeam.Id, "town-square", true)).(*model.Channel).Id - initialNumTownSquareUsers := len(store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId)).([]*model.ChannelMemberHistory)) + initialNumTownSquareUsers := len(store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId)).([]*model.ChannelMemberHistoryResult)) // create a new user that joins the default channels user := th.CreateUser() th.App.JoinDefaultChannels(th.BasicTeam.Id, user, model.CHANNEL_USER_ROLE_ID, "") // there should be a ChannelMemberHistory record for the user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, initialNumTownSquareUsers+1) found := false @@ -142,14 +142,14 @@ func TestJoinDefaultChannelsOffTopic(t *testing.T) { // figure out the initial number of users in off-topic offTopicChannelId := store.Must(th.App.Srv.Store.Channel().GetByName(th.BasicTeam.Id, "off-topic", true)).(*model.Channel).Id - initialNumTownSquareUsers := len(store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId)).([]*model.ChannelMemberHistory)) + initialNumTownSquareUsers := len(store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId)).([]*model.ChannelMemberHistoryResult)) // create a new user that joins the default channels user := th.CreateUser() th.App.JoinDefaultChannels(th.BasicTeam.Id, user, model.CHANNEL_USER_ROLE_ID, "") // there should be a ChannelMemberHistory record for the user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, initialNumTownSquareUsers+1) found := false @@ -170,7 +170,7 @@ func TestCreateChannelPublic(t *testing.T) { publicChannel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) // there should be a ChannelMemberHistory record for the user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 1) assert.Equal(t, th.BasicUser.Id, histories[0].UserId) assert.Equal(t, publicChannel.Id, histories[0].ChannelId) @@ -184,7 +184,7 @@ func TestCreateChannelPrivate(t *testing.T) { privateChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE) // there should be a ChannelMemberHistory record for the user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, privateChannel.Id)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, privateChannel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 1) assert.Equal(t, th.BasicUser.Id, histories[0].UserId) assert.Equal(t, privateChannel.Id, histories[0].ChannelId) @@ -221,7 +221,7 @@ func TestCreateGroupChannel(t *testing.T) { t.Fatal("Failed to create group channel. Error: " + err.Message) } else { // there should be a ChannelMemberHistory record for each user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 3) channelMemberHistoryUserIds := make([]string, 0) @@ -253,7 +253,7 @@ func TestAddUserToChannel(t *testing.T) { } // there should be a ChannelMemberHistory record for the user - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 2) channelMemberHistoryUserIds := make([]string, 0) for _, history := range histories { @@ -269,7 +269,7 @@ func TestRemoveUserFromChannel(t *testing.T) { // a user creates a channel publicChannel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) - histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistory) + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 1) assert.Equal(t, th.BasicUser.Id, histories[0].UserId) assert.Equal(t, publicChannel.Id, histories[0].ChannelId) @@ -279,7 +279,7 @@ func TestRemoveUserFromChannel(t *testing.T) { if err := th.App.LeaveChannel(publicChannel.Id, th.BasicUser.Id); err != nil { t.Fatal("Failed to remove user from channel. Error: " + err.Message) } - histories = store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistory) + histories = store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, histories, 1) assert.Equal(t, th.BasicUser.Id, histories[0].UserId) assert.Equal(t, publicChannel.Id, histories[0].ChannelId) diff --git a/model/ChannelMemberHistoryResult.go b/model/ChannelMemberHistoryResult.go new file mode 100644 index 000000000..ed3e79639 --- /dev/null +++ b/model/ChannelMemberHistoryResult.go @@ -0,0 +1,15 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +type ChannelMemberHistoryResult struct { + ChannelId string + UserId string + JoinTime int64 + LeaveTime *int64 + + // these two fields are never set in the database - when we SELECT, we join on Users to get them + UserEmail string `db:"Email"` + Username string +} diff --git a/model/channel_member_history.go b/model/channel_member_history.go index 47c59d54e..55435c320 100644 --- a/model/channel_member_history.go +++ b/model/channel_member_history.go @@ -8,8 +8,4 @@ type ChannelMemberHistory struct { UserId string JoinTime int64 LeaveTime *int64 - - // these two fields are never set in the database - when we SELECT, we join on Users to get them - UserEmail string `db:"Email"` - Username string } diff --git a/store/sqlstore/channel_member_history_store.go b/store/sqlstore/channel_member_history_store.go index 0b86aac28..6fc78b514 100644 --- a/store/sqlstore/channel_member_history_store.go +++ b/store/sqlstore/channel_member_history_store.go @@ -106,7 +106,7 @@ func (s SqlChannelMemberHistoryStore) hasDataAtOrBefore(time int64) (bool, error } } -func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistory, error) { +func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistoryResult, error) { query := ` SELECT cmh.*, @@ -120,7 +120,7 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime ORDER BY cmh.JoinTime ASC` params := map[string]interface{}{"ChannelId": channelId, "StartTime": startTime, "EndTime": endTime} - var histories []*model.ChannelMemberHistory + var histories []*model.ChannelMemberHistoryResult if _, err := s.GetReplica().Select(&histories, query, params); err != nil { return nil, err } else { @@ -128,7 +128,7 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime } } -func (s SqlChannelMemberHistoryStore) getFromChannelMembersTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistory, error) { +func (s SqlChannelMemberHistoryStore) getFromChannelMembersTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistoryResult, error) { query := ` SELECT DISTINCT ch.ChannelId, @@ -140,7 +140,7 @@ func (s SqlChannelMemberHistoryStore) getFromChannelMembersTable(startTime int64 WHERE ch.ChannelId = :ChannelId` params := map[string]interface{}{"ChannelId": channelId} - var histories []*model.ChannelMemberHistory + var histories []*model.ChannelMemberHistoryResult if _, err := s.GetReplica().Select(&histories, query, params); err != nil { return nil, err } else { diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index 56fdf9d6c..09f2c9160 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -346,6 +346,8 @@ func UpgradeDatabaseToVersion47(sqlStore SqlStore) { if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) { sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)") sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)") + sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email") + sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Username") saveSchemaVersion(sqlStore, VERSION_4_7_0) } } diff --git a/store/storetest/channel_member_history_store.go b/store/storetest/channel_member_history_store.go index fa2e7a8fa..b79e84fd8 100644 --- a/store/storetest/channel_member_history_store.go +++ b/store/storetest/channel_member_history_store.go @@ -102,11 +102,11 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) { store.Must(ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, joinTime)) // case 1: user joins and leaves the channel before the export period begins - channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 0) // case 2: user joins the channel after the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -116,7 +116,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) { assert.Nil(t, channelMembers[0].LeaveTime) // case 3: user joins the channel before the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -129,7 +129,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) { store.Must(ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, leaveTime)) // case 4: user joins the channel before the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -139,7 +139,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) { assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime) // case 5: user joins the channel after the export period begins, and leaves the channel before the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -149,7 +149,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) { assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime) // case 6: user has joined and left the channel long before the export period begins - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 0) } @@ -195,7 +195,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { // the past, even though the time that they were actually in the channel doesn't necessarily overlap with the export period // case 1: user joins and leaves the channel before the export period begins - channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -205,7 +205,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { assert.Equal(t, joinTime-100, *channelMembers[0].LeaveTime) // case 2: user joins the channel after the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -215,7 +215,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime) // case 3: user joins the channel before the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -225,7 +225,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime) // case 4: user joins the channel before the export period begins, but has not yet left the channel when the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -235,7 +235,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { assert.Equal(t, leaveTime-100, *channelMembers[0].LeaveTime) // case 5: user joins the channel after the export period begins, and leaves the channel before the export period ends - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -245,7 +245,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) { assert.Equal(t, leaveTime+100, *channelMembers[0].LeaveTime) // case 6: user has joined and left the channel long before the export period begins - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, channel.Id, channelMembers[0].ChannelId) assert.Equal(t, user.Id, channelMembers[0].UserId) @@ -290,7 +290,7 @@ func testPermanentDeleteBatch(t *testing.T, ss store.Store) { store.Must(ss.ChannelMemberHistory().LogJoinEvent(user2.Id, channel.Id, joinTime)) // in between the join time and the leave time, both users were members of the channel - channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 2) // the permanent delete should delete at least one record @@ -298,7 +298,7 @@ func testPermanentDeleteBatch(t *testing.T, ss store.Store) { assert.NotEqual(t, int64(0), rowsDeleted) // after the delete, there should be one less member in the channel - channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory) + channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistoryResult) assert.Len(t, channelMembers, 1) assert.Equal(t, user2.Id, channelMembers[0].UserId) } -- cgit v1.2.3-1-g7c22 From 445a356d0dc958a8fb72fd9835816302260595a2 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Mon, 12 Feb 2018 23:08:38 +0000 Subject: translations PR 20180212 --- i18n/de.json | 22 +++++------ i18n/en.json | 4 +- i18n/es.json | 20 ++++------ i18n/fr.json | 68 ++++++++++++++++----------------- i18n/it.json | 20 ++++------ i18n/ja.json | 20 ++++------ i18n/ko.json | 22 +++++------ i18n/nl.json | 114 +++++++++++++++++++++++++++----------------------------- i18n/pl.json | 20 ++++------ i18n/pt-BR.json | 20 ++++------ i18n/ru.json | 36 ++++++++---------- i18n/tr.json | 20 ++++------ i18n/zh-CN.json | 20 ++++------ i18n/zh-TW.json | 30 +++++++-------- 14 files changed, 192 insertions(+), 244 deletions(-) diff --git a/i18n/de.json b/i18n/de.json index b506e7018..4f9ac581f 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -2184,7 +2184,7 @@ }, { "id": "api.team.add_user_to_team.added", - "translation": "%v wurde von %v zum Team hinzugefügt" + "translation": "%v wurde von %v zum Team hinzugefügt." }, { "id": "api.team.add_user_to_team.missing_parameter.app_error", @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Der Link ist abgelaufen" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Der Einladungslink scheint nicht gültig zu sein" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Diese URL ist nicht verfügbar. Bitte wähle eine andere." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Der Registrierungslink scheint nicht gültig zu sein" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Ungültiger Teamname" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Ungültige Thumbnauilbreite in Dateieinstellungen. Muss eine positive Zahl sein." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Ungültige Diensteinstellungen für Gruppierung von ungelesenen Kanälen. Muss 'disabled', 'default_on' oder default_off' sein." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Ungültiger Bild-Proxy-Typ für Diensteinstellungen." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Registrieren" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Der Registrierungslink scheint nicht gültig zu sein" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Der Registrierungslink ist abgelaufen" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Der Registrierungslink ist abgelaufen" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Der Registrierungslink scheint nicht gültig zu sein" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "Dieser Teamtyp erlaubt keine offnen Einladungen" diff --git a/i18n/en.json b/i18n/en.json index 4365a44fb..41fd9d982 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2703,11 +2703,11 @@ "translation": "The signup link has expired" }, { - "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "The signup link does not appear to be valid" }, { - "id": "api.user.create_user.signup_link_invalid.app_error", + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", "translation": "The signup link does not appear to be valid" }, { diff --git a/i18n/es.json b/i18n/es.json index c96674885..b3d472b9f 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "El enlace de registro ha expirado" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "El enlace de registro parece ser inválido" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Este URL no está disponible. Por favor, prueba con otra." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "El enlace de registro parece ser inválido" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Nombre del equipo inválido" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "El ancho para la imagen de miniatura es inválido en la configuración de archivos. Debe ser un número positivo." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Ajuste invalido para el agrupamiento de canales no leídos en la configuración de servicio. Debe ser 'disabled', 'default_on' o 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Tipo de proxy para las imágenes no válido en la configuración del servicio." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Registrar" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "El enlace de registro parece ser inválido" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "El enlace de registro ha expirado" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "El enlace de registro ha expirado" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "El enlace de registro parece ser inválido" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "El tipo de equipo no permite realizar invitaciones" diff --git a/i18n/fr.json b/i18n/fr.json index f2c20c29f..66a414e64 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -153,7 +153,7 @@ }, { "id": "api.channel.add_member.added", - "translation": "%v a été ajouté au canal par %v" + "translation": "%v a été ajouté au canal par %v." }, { "id": "api.channel.add_member.find_channel.app_error", @@ -201,11 +201,11 @@ }, { "id": "api.channel.change_channel_privacy.private_to_public", - "translation": "This channel has been converted to a Public Channel and can be joined by any team member." + "translation": "Ce canal a été converti en canal public et peut être rejoint par tout membre de l'équipe." }, { "id": "api.channel.change_channel_privacy.public_to_private", - "translation": "This channel has been converted to a Private Channel." + "translation": "Ce canal a été converti en canal privé." }, { "id": "api.channel.create_channel.direct_channel.app_error", @@ -2184,7 +2184,7 @@ }, { "id": "api.team.add_user_to_team.added", - "translation": "%v a été ajouté à l'équipe par %v" + "translation": "%v a été ajouté à l'équipe par %v." }, { "id": "api.team.add_user_to_team.missing_parameter.app_error", @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Le lien d'inscription a expiré." }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Le lien d'inscription semble ne pas être valide." - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Cette URL n'est pas disponible. Veuillez en essayer une autre." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Le lien d'enregistrement n'est pas valide." }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Nom d'équipe incorrect" @@ -2956,7 +2956,7 @@ }, { "id": "api.user.upload_profile_user.decode_config.app_error", - "translation": "Impossible de sauvegarder l'image de profile. Le fichier ne semble pas être un fichier d'image valide." + "translation": "Impossible de sauvegarder l'image de profil. Le fichier ne semble pas être un fichier d'image valide." }, { "id": "api.user.upload_profile_user.encode.app_error", @@ -3360,7 +3360,7 @@ }, { "id": "app.import.validate_post_import_data.create_at_zero.error", - "translation": "La propriété de message CreateAt ne doit pas être 0 si ce champ est défini." + "translation": "La propriété de message CreateAt ne doit pas être 0." }, { "id": "app.import.validate_post_import_data.message_length.error", @@ -3380,51 +3380,51 @@ }, { "id": "app.import.validate_reaction_import_data.create_at_before_parent.error", - "translation": "Reaction CreateAt property must be greater than the parent post CreateAt." + "translation": "La propriété de réponse CreateAt doit être plus grande que la valeur de la propriété CreateAt parente." }, { "id": "app.import.validate_reaction_import_data.create_at_missing.error", - "translation": "La propriété requise pour un message est manquante : create_at." + "translation": "La propriété requise de réaction est manquante : create_at." }, { "id": "app.import.validate_reaction_import_data.create_at_zero.error", - "translation": "La propriété de message CreateAt ne doit pas être 0 si ce champ est défini." + "translation": "La propriété de réaction CreateAt ne doit pas être 0." }, { "id": "app.import.validate_reaction_import_data.emoji_name_length.error", - "translation": "La propriété Message du message est plus longue que la longueur maximale autorisée." + "translation": "La propriété de réaction EmojiName est plus longue que la longueur maximale autorisée." }, { "id": "app.import.validate_reaction_import_data.emoji_name_missing.error", - "translation": "La propriété requise du message est manquante : User." + "translation": "La propriété requise de réaction est manquante : EmojiName." }, { "id": "app.import.validate_reaction_import_data.user_missing.error", - "translation": "La propriété requise du message est manquante : User." + "translation": "La propriété requise de réaction est manquante : User." }, { "id": "app.import.validate_reply_import_data.create_at_before_parent.error", - "translation": "Reply CreateAt property must be greater than the parent post CreateAt." + "translation": "La propriété de réponse CreateAt doit être plus grande que la valeur de la propriété CreateAt parente." }, { "id": "app.import.validate_reply_import_data.create_at_missing.error", - "translation": "La propriété requise pour un message est manquante : create_at." + "translation": "La propriété requise de réponse est manquante : create_at." }, { "id": "app.import.validate_reply_import_data.create_at_zero.error", - "translation": "La propriété de message CreateAt ne doit pas être 0 si ce champ est défini." + "translation": "La propriété de message CreateAt ne doit pas être 0." }, { "id": "app.import.validate_reply_import_data.message_length.error", - "translation": "La propriété Message du message est plus longue que la longueur maximale autorisée." + "translation": "La propriété de réponse Message est plus longue que la longueur maximale autorisée." }, { "id": "app.import.validate_reply_import_data.message_missing.error", - "translation": "La propriété requise du message est manquante : Message." + "translation": "La propriété requise de réponse est manquante : Message." }, { "id": "app.import.validate_reply_import_data.user_missing.error", - "translation": "La propriété requise du message est manquante : User." + "translation": "La propriété requise de réponse est manquante : User." }, { "id": "app.import.validate_team_import_data.allowed_domains_length.error", @@ -3564,7 +3564,7 @@ }, { "id": "app.import.validate_user_import_data.profile_image.error", - "translation": "Invalid profile image." + "translation": "Image de profil invalide." }, { "id": "app.import.validate_user_import_data.roles_invalid.error", @@ -4644,7 +4644,7 @@ }, { "id": "model.config.is_valid.atmos_camo_image_proxy_options.app_error", - "translation": "Invalid atmos/camo image proxy options for service settings. Must be set to your shared key." + "translation": "Les paramètres d'options du proxy d'image atmos/camo sont invalides. Votre clé partagée doit être définie comme paramètre." }, { "id": "model.config.is_valid.cluster_email_batching.app_error", @@ -4758,9 +4758,13 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Largeur des miniatures invalide dans les paramètres de fichiers. Doit être un entier positif." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Le paramètre de groupement de canaux non lus est invalide. Doit être défini sur « disabled », « default_on » ou « default_off »." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", - "translation": "Invalid image proxy type for service settings." + "translation": "Paramètre de type de proxy d'image invalide." }, { "id": "model.config.is_valid.ldap_basedn", @@ -5404,7 +5408,7 @@ }, { "id": "model.user.is_valid.position.app_error", - "translation": "Rôle invalide : ne doit pas faire plus de 35 caractères." + "translation": "Rôle invalide : ne doit pas faire plus de 128 caractères." }, { "id": "model.user.is_valid.pwd.app_error", @@ -6848,7 +6852,7 @@ }, { "id": "store.sql_user_access_token.get_all.app_error", - "translation": "Impossible de récupérer le jeton d'accès personnel" + "translation": "Impossible de récupérer tous les jetons d'accès personnel" }, { "id": "store.sql_user_access_token.get_by_token.app_error", @@ -6864,7 +6868,7 @@ }, { "id": "store.sql_user_access_token.search.app_error", - "translation": "Nous avons rencontré une erreur lors de la recherche du jeton d'accès" + "translation": "Nous avons rencontré une erreur lors de la recherche des jetons d'accès personnel" }, { "id": "store.sql_webhooks.analytics_incoming_count.app_error", @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Inscription" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Le lien d'inscription ne semble pas être valide" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Le lien d'inscription a expiré" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Le lien d'inscription a expiré" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Le lien d'inscription ne semble pas être valide" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "Le type d'équipe ne permet pas les invitations ouvertes" diff --git a/i18n/it.json b/i18n/it.json index a58dfa15a..c2f62ae5d 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Il collegamento per l'iscrizione è scaduto" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Il collegamento per l'iscrizione non sembra essere valido" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "L'URL non è disponibile. Provane un altro." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Il collegamento per l'iscrizione non sembra essere valido" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Nome gruppo non valido" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Larghezza antemprima non valida per le impostazioni file. Deve essere un numero positivo." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Canali non letti del gruppo non validi per le impostazioni del servizio. Dev'essere 'disabled', 'default_on' oppure 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Tipo proxy immagine non valido nelle impostazioni del servizio." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Iscrizione" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Il collegamento per l'iscrizione non sembra essere valido" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Il collegamento per l'iscrizione è scaduto" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Il collegamento per l'iscrizione è scaduto" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Il collegamento per l'iscrizione non sembra essere valido" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "La tipologia del gruppo non ammette inviti aperti" diff --git a/i18n/ja.json b/i18n/ja.json index 3017f94dc..c525f471b 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "利用登録リンクは有効期限が切れています" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "利用登録リンクが不正です" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "このURLは利用できません。他のURLを試してみてください。" @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "利用登録リンクが不正です" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "不正なチーム名です" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "ファイル設定のサムネイルの幅が不正です。ゼロ以上の数を指定してください。" }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "未読チャンネルのグループ化設定が不正です。'disabled', 'default_on', 'default_off'のいずれかでなくてはなりません。" + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "画像プロキシタイプの設定が不正です。" @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "利用登録" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "利用登録リンクが不正です" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "利用登録リンクの期限が切れています" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "利用登録リンクの期限が切れています" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "利用登録リンクが不正です" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "このチームは誰でも招待できるような形式ではありません" diff --git a/i18n/ko.json b/i18n/ko.json index bdd2935a4..68fb33734 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "가입 링크가 만료되었습니다." }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "유효하지 않은 가입 링크입니다." - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "유효하지 않는 URL 입니다. 변경 후 다시 시도해주세요." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "유효하지 않은 가입 링크입니다." }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "올바르지 않은 팀 이름" @@ -3136,7 +3136,7 @@ }, { "id": "app.channel.post_update_channel_purpose_message.post.error", - "translation": "Failed to post channel purpose message" + "translation": "들어옴/나감 메시지를 등록하는 데 실패함" }, { "id": "app.channel.post_update_channel_purpose_message.removed", @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "파일 세팅에 대한 잘못된 썸네일 너비값입니다. 0보다 큰 값이여야 합니다." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Invalid image proxy type for service settings." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "가입" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "유효하지 않은 가입 링크입니다." - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "가입 링크가 만료되었습니다." @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "가입 링크가 만료되었습니다." }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "유효하지 않은 가입 링크입니다." - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "The team type doesn't allow open invites" diff --git a/i18n/nl.json b/i18n/nl.json index 2e0f54ee4..2e02433e4 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -49,7 +49,7 @@ }, { "id": "api.admin.add_certificate.no_file.app_error", - "translation": "Geen bestand in 'certificate' veld in aanvraag" + "translation": "Geen bestand gevonden in 'certificate' veld in verzoek" }, { "id": "api.admin.add_certificate.open.app_error", @@ -57,15 +57,15 @@ }, { "id": "api.admin.add_certificate.saving.app_error", - "translation": "Kon het certificaat-bestand niet opslaan" + "translation": "Kon het certificaat-bestand niet opslaan." }, { "id": "api.admin.file_read_error", - "translation": "Fout bij lezen van logbestand" + "translation": "Fout bij lezen van logbestand." }, { "id": "api.admin.get_brand_image.not_available.app_error", - "translation": "Personaliseren is niet ondersteund, of niet geconfigureerd op deze server" + "translation": "Personalisatie is niet ondersteund of niet geconfigureerd op deze server." }, { "id": "api.admin.get_brand_image.storage.app_error", @@ -73,15 +73,15 @@ }, { "id": "api.admin.init.debug", - "translation": "Initialisatie van de admin API routes" + "translation": "Initialisatie van de admin API routes." }, { "id": "api.admin.recycle_db_end.warn", - "translation": "Klaar met herstarten van de databaseverbinding" + "translation": "Klaar met herstarten van de databaseverbinding." }, { "id": "api.admin.recycle_db_start.warn", - "translation": "Proberen om de databaseverbinding te herstarten" + "translation": "Proberen om de databaseverbinding te herstarten." }, { "id": "api.admin.remove_certificate.delete.app_error", @@ -89,7 +89,7 @@ }, { "id": "api.admin.saml.metadata.app_error", - "translation": "Er is een fout opgetreden tijdens het opstellen van Service Provider Metadata." + "translation": "Er is een fout opgetreden tijdens het opzetten van Service Provider Metadata." }, { "id": "api.admin.test_email.body", @@ -153,7 +153,7 @@ }, { "id": "api.channel.add_member.added", - "translation": "%v is door %v aan het kanaal toegevoegd" + "translation": "%v is door %v aan het kanaal toegevoegd." }, { "id": "api.channel.add_member.find_channel.app_error", @@ -185,11 +185,11 @@ }, { "id": "api.channel.can_manage_channel.private_restricted_system_admin.app_error", - "translation": "Alleen systeembeheerders mogen publieke kanalen beheren en aanmaken." + "translation": "Alleen systeembeheerders mogen privékanalen beheren en aanmaken." }, { "id": "api.channel.can_manage_channel.private_restricted_team_admin.app_error", - "translation": "Alleen team- en systeembeheerders mogen publieke kanalen beheren en aanmaken." + "translation": "Alleen team- en systeembeheerders mogen privékanalen beheren en aanmaken." }, { "id": "api.channel.can_manage_channel.public_restricted_system_admin.app_error", @@ -201,11 +201,11 @@ }, { "id": "api.channel.change_channel_privacy.private_to_public", - "translation": "This channel has been converted to a Public Channel and can be joined by any team member." + "translation": "Dit kanaal is omgezet naar een publiek kanaal en is open voor ieder teamlid." }, { "id": "api.channel.change_channel_privacy.public_to_private", - "translation": "This channel has been converted to a Private Channel." + "translation": "This kanaal is omgezet naar een privékanaal." }, { "id": "api.channel.create_channel.direct_channel.app_error", @@ -229,15 +229,15 @@ }, { "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "Invalid user ID for direct channel creation" + "translation": "Onjuiste gebruikers ID voor het aanmaken van een direct kanaal." }, { "id": "api.channel.create_group.bad_size.app_error", - "translation": "Group message channels must contain at least 3 and no more than 8 users" + "translation": "Groep bericht kanalen moeten tenminste 3 en niet meer dan 8 gebruikers bevatten" }, { "id": "api.channel.create_group.bad_user.app_error", - "translation": "One of the provided users does not exist" + "translation": "Een van de opgegeven gebruikers bestaat niet" }, { "id": "api.channel.delete_channel.archived", @@ -305,7 +305,7 @@ }, { "id": "api.channel.join_channel.post_and_forget", - "translation": "%v is het kanaal binnengekomen." + "translation": "%v is nu lid van het kanaal." }, { "id": "api.channel.leave.default.app_error", @@ -317,7 +317,7 @@ }, { "id": "api.channel.leave.last_member.app_error", - "translation": "U bent het laatste lid, probeer de privégroep te verwijderen in plaats van die te verlaten." + "translation": "U bent het laatste lid, probeer de privékanaalte verwijderen in plaats van die te verlaten." }, { "id": "api.channel.leave.left", @@ -329,7 +329,7 @@ }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", - "translation": "Kon de gebruiker niet ophalen tijdens het bewaren van de nieuwe kanaalkoptekst %v" + "translation": "Kon de gebruiker niet ophalen tijdens het bijwerken van het kanaal weergavenaam veld" }, { "id": "api.channel.post_update_channel_displayname_message_and_forget.updated_from", @@ -337,7 +337,7 @@ }, { "id": "api.channel.post_update_channel_header_message_and_forget.post.error", - "translation": "Failed to post update channel header message" + "translation": "Kanaalkoptekst bijwerken mislukt" }, { "id": "api.channel.post_update_channel_header_message_and_forget.removed", @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "De aanmeld link is verlopen" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "De aanmeld link is niet geldig" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Deze URL is niet beschikbaar. Probeer een andere." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "De aanmeld link is niet geldig" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Ongeldige team naam" @@ -3136,7 +3136,7 @@ }, { "id": "app.channel.post_update_channel_purpose_message.post.error", - "translation": "Failed to post channel purpose message" + "translation": "Plaatsen van bericht over binnenkomen/verlaten %v is mislukt" }, { "id": "app.channel.post_update_channel_purpose_message.removed", @@ -3204,7 +3204,7 @@ }, { "id": "app.import.import_line.null_channel.error", - "translation": "Import data line has type \"channel\" but the channel object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.null_direct_channel.error", @@ -3216,15 +3216,15 @@ }, { "id": "app.import.import_line.null_post.error", - "translation": "Import data line has type \"post\" but the post object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.null_team.error", - "translation": "Import data line has type \"team\" but the team object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.null_user.error", - "translation": "Import data line has type \"user\" but the user object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.unknown_line_type.error", @@ -3252,7 +3252,7 @@ }, { "id": "app.import.validate_channel_import_data.create_at_zero.error", - "translation": "Channel create_at must not be zero if provided." + "translation": "Kanaaleigenschap create_at mag niet 0 zijn indien opgegeven." }, { "id": "app.import.validate_channel_import_data.display_name_length.error", @@ -3276,7 +3276,7 @@ }, { "id": "app.import.validate_channel_import_data.name_missing.error", - "translation": "Missing required channel property: name" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_channel_import_data.purpose_length.error", @@ -3292,7 +3292,7 @@ }, { "id": "app.import.validate_channel_import_data.type_missing.error", - "translation": "Missing required channel property: type." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_direct_channel_import_data.header_length.error", @@ -3352,7 +3352,7 @@ }, { "id": "app.import.validate_post_import_data.channel_missing.error", - "translation": "Missing required Post property: Channel." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_post_import_data.create_at_missing.error", @@ -3368,19 +3368,19 @@ }, { "id": "app.import.validate_post_import_data.message_missing.error", - "translation": "Missing required Post property: Message." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_post_import_data.team_missing.error", - "translation": "Missing required Post property: Team." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_post_import_data.user_missing.error", - "translation": "Missing required Post property: User." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reaction_import_data.create_at_before_parent.error", - "translation": "Reaction CreateAt property must be greater than the parent post CreateAt." + "translation": "Reactie CreateAt eigenschap moet groter zijn dan het hoofdbericht CreateAt" }, { "id": "app.import.validate_reaction_import_data.create_at_missing.error", @@ -3400,11 +3400,11 @@ }, { "id": "app.import.validate_reaction_import_data.user_missing.error", - "translation": "Missing required Reaction property: User." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reply_import_data.create_at_before_parent.error", - "translation": "Reply CreateAt property must be greater than the parent post CreateAt." + "translation": "Reactie CreateAt eigenschap moet groter zijn dan het hoofdbericht CreateAt" }, { "id": "app.import.validate_reply_import_data.create_at_missing.error", @@ -3420,11 +3420,11 @@ }, { "id": "app.import.validate_reply_import_data.message_missing.error", - "translation": "Missing required Reply property: Message." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reply_import_data.user_missing.error", - "translation": "Missing required Reply property: User." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_team_import_data.allowed_domains_length.error", @@ -3432,7 +3432,7 @@ }, { "id": "app.import.validate_team_import_data.create_at_zero.error", - "translation": "Team create_at must not be zero if provided." + "translation": "Kanaaleigenschap create_at mag niet 0 zijn indien opgegeven." }, { "id": "app.import.validate_team_import_data.description_length.error", @@ -3444,7 +3444,7 @@ }, { "id": "app.import.validate_team_import_data.display_name_missing.error", - "translation": "Missing required team property: display_name." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_team_import_data.name_characters.error", @@ -3456,7 +3456,7 @@ }, { "id": "app.import.validate_team_import_data.name_missing.error", - "translation": "Missing required team property: name." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_team_import_data.name_reserved.error", @@ -3468,7 +3468,7 @@ }, { "id": "app.import.validate_team_import_data.type_missing.error", - "translation": "Missing required team property: type." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_user_channels_import_data.channel_name_missing.error", @@ -3508,7 +3508,7 @@ }, { "id": "app.import.validate_user_import_data.email_missing.error", - "translation": "Missing required user property: email." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_user_import_data.first_name_length.error", @@ -3576,7 +3576,7 @@ }, { "id": "app.import.validate_user_import_data.username_missing.error", - "translation": "Missing require user property: username." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_user_teams_import_data.invalid_roles.error", @@ -4028,7 +4028,7 @@ }, { "id": "ent.elasticsearch.test_config.connect_failed", - "translation": "Connecting to Elasticsearch server failed." + "translation": "Connectie naar Elasticsearch server is mislukt." }, { "id": "ent.elasticsearch.test_config.indexing_disabled.error", @@ -4672,7 +4672,7 @@ }, { "id": "model.config.is_valid.elastic_search.connection_url.app_error", - "translation": "Elastic Search ConnectionUrl setting must be provided when Elastic Search indexing is enabled." + "translation": "Elastic Search Username instelling moet ingevuld zijn wanneer Elastic Search indexing is ingeschakeld." }, { "id": "model.config.is_valid.elastic_search.enable_searching.app_error", @@ -4684,7 +4684,7 @@ }, { "id": "model.config.is_valid.elastic_search.password.app_error", - "translation": "Elastic Search Password setting must be provided when Elastic Search indexing is enabled." + "translation": "Elastic Search Username instelling moet ingevuld zijn wanneer Elastic Search indexing is ingeschakeld." }, { "id": "model.config.is_valid.elastic_search.posts_aggregator_job_start_time.app_error", @@ -4696,7 +4696,7 @@ }, { "id": "model.config.is_valid.elastic_search.username.app_error", - "translation": "Elastic Search Username setting must be provided when Elastic Search indexing is enabled." + "translation": "Elastic Search Username instelling moet ingevuld zijn wanneer Elastic Search indexing is ingeschakeld." }, { "id": "model.config.is_valid.email_batching_buffer_size.app_error", @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Ongeldige voorvertonings breedte bij bestands instellingen. Moet een getal groter dan 0 zijn." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Invalid image proxy type for service settings." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Aanmelden" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "De aanmeld link is niet geldig" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "De aanmeld link is verlopen" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "De aanmeld link is verlopen" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "De aanmeld link is niet geldig" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "Het team type staat open uitnodiging niet toe" diff --git a/i18n/pl.json b/i18n/pl.json index ccf9fed39..d149f38b0 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Odnośnik zapisu jest przeterminowany" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Odnośnik zapisu nie wydaje się być poprawny" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Ten adres URL jest niedostępny. Proszę wybrać inny." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Link rejestracyjny wydaje się być niepoprawny" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Niepoprawna nazwa zespołu" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Nieprawidłowa szerokość miniaturki dla ustawień plików. Musi być liczbą większą od 0." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Invalid image proxy type for service settings." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Rejestracja" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Link do rejestracji jest niepoprawny" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Link do rejestracji wygasł" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Link do rejestracji wygasł" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Link do rejestracji jest niepoprawny" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "The team type doesn't allow open invites" diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index b07cb452e..3ec45c2eb 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "O link de inscrição expirou" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "O link de inscrição não parece ser válido" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Esta URL não está disponível. Por favor, tente outra." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "O link de inscrição não parece ser válido" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Inválido nome de equipe" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Definição da largura do thumbnail inválida. Deve ser um número positivo." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Grupo de canais não lidos inválido nas configurações do serviço. Deve ser 'disabled', 'default_on', ou 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Tipo de proxy de imagem inválido nas configurações de serviços." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Inscrever-se" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "O link de inscrição não parece ser válido" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "O link de inscrição expirou" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "O link de inscrição expirou" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "O link de inscrição não parece ser válido" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "O tipo da equipe não permite convites abertos" diff --git a/i18n/ru.json b/i18n/ru.json index b1e37d191..cb4d26d45 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -201,11 +201,11 @@ }, { "id": "api.channel.change_channel_privacy.private_to_public", - "translation": "This channel has been converted to a Public Channel and can be joined by any team member." + "translation": "Канал преобразован в публичный и к нему может присоединиться любой участник." }, { "id": "api.channel.change_channel_privacy.public_to_private", - "translation": "This channel has been converted to a Private Channel." + "translation": "Канал преобразован в приватный." }, { "id": "api.channel.create_channel.direct_channel.app_error", @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Ссылка на регистрацию устарела" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Неправильная ссылка на регистрацию" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Этот URL-адрес недоступен. Пожалуйста, попробуйте другой." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Ссылка для регистрации, похоже, неверна." }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Неверное имя команды" @@ -3248,7 +3248,7 @@ }, { "id": "app.import.import_user_channels.save_preferences.error", - "translation": "Error importing user channel memberships. Failed to save preferences." + "translation": "Ошибка импорта участия пользователя в каналах. Не удалось сохранить настройки." }, { "id": "app.import.validate_channel_import_data.create_at_zero.error", @@ -3296,7 +3296,7 @@ }, { "id": "app.import.validate_direct_channel_import_data.header_length.error", - "translation": "Direct channel header is too long" + "translation": "Заголовок личного канала слишком длинный." }, { "id": "app.import.validate_direct_channel_import_data.members_required.error", @@ -3304,11 +3304,11 @@ }, { "id": "app.import.validate_direct_channel_import_data.members_too_few.error", - "translation": "Direct channel members list contains too few items" + "translation": "В списке пользователей личного канала слишком мало элементов." }, { "id": "app.import.validate_direct_channel_import_data.members_too_many.error", - "translation": "Direct channel members list contains too many items" + "translation": "В списке пользователей личного канала слишком много элементов." }, { "id": "app.import.validate_direct_channel_import_data.unknown_favoriter.error", @@ -3320,11 +3320,11 @@ }, { "id": "app.import.validate_direct_post_import_data.channel_members_too_few.error", - "translation": "Direct post channel members list contains too few items" + "translation": "В списке пользователей личного канала слишком мало элементов." }, { "id": "app.import.validate_direct_post_import_data.channel_members_too_many.error", - "translation": "Direct post channel members list contains too many items" + "translation": "В списке пользователей личного канала слишком много элементов." }, { "id": "app.import.validate_direct_post_import_data.create_at_missing.error", @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Неверная ширина миниатюры в настройках файлов. Число должно быть положительным." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Invalid image proxy type for service settings." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Регистрация" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Ссылка для регистрации, похоже, недействительна" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Ссылка для регистрации устарела" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Ссылка для регистрации устарела" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Ссылка для регистрации, похоже, недействительна" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "Тип команды не позволяет открытые приглашения" diff --git a/i18n/tr.json b/i18n/tr.json index b95c9b542..ae782ddb4 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "Hesap açma bağlantısının süresi geçmiş" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "Hesap açma bağlantısı geçersiz görünüyor" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "Adres kullanılamıyor. Lütfen yeniden deneyin." @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "Hesap açma bağlantısı geçersiz görünüyor" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "Takım adı geçersiz" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "Küçük görsel genişliği dosya ayarı geçersiz. Sıfır ya da pozitif bir sayı olmalı." }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Hizmet ayarları okunmamış kanallar gruplansın geçersiz. 'disabled', 'default_on' ya da 'default_off' olmalıdır." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "Hizmet ayarlarında görsel vekil sunucu türü geçersiz." @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "Hesap Açın" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "Hesap açma bağlantısı geçersiz görünüyor" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "Hesap açma bağlantısının süresi geçmiş" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "Hesap açma bağlantısının süresi geçmiş" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "Hesap açma bağlantısı geçersiz görünüyor" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "Takım türü açık çağrılara izin vermiyor" diff --git a/i18n/zh-CN.json b/i18n/zh-CN.json index fb484b50d..9186f936e 100644 --- a/i18n/zh-CN.json +++ b/i18n/zh-CN.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "注册链接已过期" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "注册链接无效" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "该URL无效。请尝试其他。" @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "注册链接无效" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "无效团队名称" @@ -4758,6 +4758,10 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "文件设置时缩略图宽度无效。必须是正数。" }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + }, { "id": "model.config.is_valid.image_proxy_type.app_error", "translation": "无效的图片代理类型服务设定。" @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "注册" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "注册链接无效" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "注册链接已过期" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "注册链接已过期" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "注册链接无效" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "团队类型不允许公开邀请" diff --git a/i18n/zh-TW.json b/i18n/zh-TW.json index a7387d88f..e31a35941 100644 --- a/i18n/zh-TW.json +++ b/i18n/zh-TW.json @@ -2202,10 +2202,6 @@ "id": "api.team.create_team_from_signup.expired_link.app_error", "translation": "註冊連結已過期" }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "此註冊連結不是有效連結" - }, { "id": "api.team.create_team_from_signup.unavailable.app_error", "translation": "這個網址不存在。請嘗試其他的。" @@ -2710,6 +2706,10 @@ "id": "api.user.create_user.signup_link_invalid.app_error", "translation": "此註冊連結不是有效連結" }, + { + "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", + "translation": "The signup link does not appear to be valid" + }, { "id": "api.user.create_user.team_name.app_error", "translation": "無效的團隊名稱" @@ -3564,7 +3564,7 @@ }, { "id": "app.import.validate_user_import_data.profile_image.error", - "translation": "Invalid profile image." + "translation": "無效的個人頭像。" }, { "id": "app.import.validate_user_import_data.roles_invalid.error", @@ -4644,7 +4644,7 @@ }, { "id": "model.config.is_valid.atmos_camo_image_proxy_options.app_error", - "translation": "Invalid atmos/camo image proxy options for service settings. Must be set to your shared key." + "translation": "服務設定中的 atmos/camo 圖片代理無效。必須設定為分享金鑰。" }, { "id": "model.config.is_valid.cluster_email_batching.app_error", @@ -4758,9 +4758,13 @@ "id": "model.config.is_valid.file_thumb_width.app_error", "translation": "檔案設定中縮圖寬度無效。必須為正數。" }, + { + "id": "model.config.is_valid.group_unread_channels.app_error", + "translation": "服務設定中的未讀頻道分組無效。必須為 'disabled' 、 'default_on' 或 'default_off'。" + }, { "id": "model.config.is_valid.image_proxy_type.app_error", - "translation": "Invalid image proxy type for service settings." + "translation": "服務設定中的圖片代理類型無效。" }, { "id": "model.config.is_valid.ldap_basedn", @@ -5404,7 +5408,7 @@ }, { "id": "model.user.is_valid.position.app_error", - "translation": "無效的位置:不能超過35個字元。" + "translation": "無效的位置:不能超過128個字元。" }, { "id": "model.user.is_valid.pwd.app_error", @@ -6848,7 +6852,7 @@ }, { "id": "store.sql_user_access_token.get_all.app_error", - "translation": "無法取得個人存取 Token" + "translation": "無法取得全部的個人存取 Token" }, { "id": "store.sql_user_access_token.get_by_token.app_error", @@ -7290,10 +7294,6 @@ "id": "web.root.singup_title", "translation": "註冊" }, - { - "id": "web.signup_team_complete.invalid_link.app_error", - "translation": "此註冊連結不是有效連結" - }, { "id": "web.signup_team_complete.link_expired.app_error", "translation": "註冊連結已過期" @@ -7310,10 +7310,6 @@ "id": "web.signup_user_complete.link_expired.app_error", "translation": "註冊連結已過期" }, - { - "id": "web.signup_user_complete.link_invalid.app_error", - "translation": "此註冊連結不是有效連結" - }, { "id": "web.signup_user_complete.no_invites.app_error", "translation": "此團隊類型不允許自由加入" -- cgit v1.2.3-1-g7c22 From 0cbba46018d3879234d3940e8ee6f23dd99a1c5a Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Mon, 12 Feb 2018 16:30:03 -0700 Subject: Fixes ICU-764 --- app/notification.go | 3 +++ app/notification_test.go | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/app/notification.go b/app/notification.go index 1318308f8..6531f72f7 100644 --- a/app/notification.go +++ b/app/notification.go @@ -832,6 +832,9 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit continue } + // remove trailing '.', as that is the end of a sentence + word = strings.TrimSuffix(word, ".") + if word == "@here" { ret.HereMentioned = true } diff --git a/app/notification_test.go b/app/notification_test.go index 11f4df685..7f2a63ab9 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -109,6 +109,15 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "OnePersonAtEndOfSentence": { + Message: "this is a message for @user.", + Keywords: map[string][]string{"@user": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "OnePersonWithoutAtMention": { Message: "this is a message for @user", Keywords: map[string][]string{"this": {id1}}, @@ -179,6 +188,15 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "UserWithPeriodAtEndOfSentence": { + Message: "this is a message for user.period.", + Keywords: map[string][]string{"user.period": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "PotentialOutOfChannelUser": { Message: "this is an message for @potential and @user", Keywords: map[string][]string{"@user": {id1}}, -- cgit v1.2.3-1-g7c22 From bdf478c75bb41c00cdfd47bd7ae68c70a06886af Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Mon, 12 Feb 2018 20:50:20 -0700 Subject: Added another test --- app/notification_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/notification_test.go b/app/notification_test.go index 7f2a63ab9..61442c048 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -188,6 +188,15 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "AtUserWithPeriodAtEndOfSentence": { + Message: "this is a message for @user.period.", + Keywords: map[string][]string{"@user.period": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "UserWithPeriodAtEndOfSentence": { Message: "this is a message for user.period.", Keywords: map[string][]string{"user.period": {id1}}, -- cgit v1.2.3-1-g7c22 From bda8736770f89399f4bca189bc3559f0141cab8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 13 Feb 2018 10:43:28 +0100 Subject: XYZ-111: Check max users per team on re-join after leave a team --- app/team.go | 12 ++++++-- app/team_test.go | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ i18n/en.json | 4 +++ 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/app/team.go b/app/team.go index 8e8c29e2a..a15c64c3f 100644 --- a/app/team.go +++ b/app/team.go @@ -302,10 +302,16 @@ func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMem return rtm, true, nil } - if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil { - return nil, false, tmr.Err + if membersCount := <-a.Srv.Store.Team().GetActiveMemberCount(tm.TeamId); membersCount.Err != nil { + return nil, false, membersCount.Err + } else if membersCount.Data.(int64) >= int64(*a.Config().TeamSettings.MaxUsersPerTeam) { + return nil, false, model.NewAppError("joinUserToTeam", "app.team.join_user_to_team.max_accounts.app_error", nil, "teamId="+tm.TeamId, http.StatusBadRequest) } else { - return tmr.Data.(*model.TeamMember), false, nil + if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil { + return nil, false, tmr.Err + } else { + return tmr.Data.(*model.TeamMember), false, nil + } } } else { // Membership appears to be missing. Lets try to add. diff --git a/app/team_test.go b/app/team_test.go index 7cb20b6f6..a2bf44a57 100644 --- a/app/team_test.go +++ b/app/team_test.go @@ -460,3 +460,92 @@ func TestAddUserToTeamByHashMismatchedInviteId(t *testing.T) { assert.Nil(t, team) assert.Equal(t, "api.user.create_user.signup_link_mismatched_invite_id.app_error", err.Id) } + +func TestJoinUserToTeam(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + id := model.NewId() + team := &model.Team{ + DisplayName: "dn_" + id, + Name: "name" + id, + Email: "success+" + id + "@simulator.amazonses.com", + Type: model.TEAM_OPEN, + } + + if _, err := th.App.CreateTeam(team); err != nil { + t.Log(err) + t.Fatal("Should create a new team") + } + + maxUsersPerTeam := th.App.Config().TeamSettings.MaxUsersPerTeam + defer func() { + th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = maxUsersPerTeam }) + th.App.SetDefaultRolesBasedOnConfig() + th.App.PermanentDeleteTeam(team) + }() + one := 1 + th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = &one }) + + t.Run("new join", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); alreadyAdded || err != nil { + t.Fatal("Should return already added equal to false and no error") + } + }) + + t.Run("join when you are a member", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + th.App.joinUserToTeam(team, ruser) + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); !alreadyAdded || err != nil { + t.Fatal("Should return already added and no error") + } + }) + + t.Run("re-join after leaving", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + th.App.joinUserToTeam(team, ruser) + th.App.LeaveTeam(team, ruser, ruser.Id) + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); alreadyAdded || err != nil { + t.Fatal("Should return already added equal to false and no error") + } + }) + + t.Run("new join with limit problem", func(t *testing.T) { + user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser1, _ := th.App.CreateUser(&user1) + user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser2, _ := th.App.CreateUser(&user2) + defer th.App.PermanentDeleteUser(&user1) + defer th.App.PermanentDeleteUser(&user2) + th.App.joinUserToTeam(team, ruser1) + if _, _, err := th.App.joinUserToTeam(team, ruser2); err == nil { + t.Fatal("Should fail") + } + }) + + t.Run("re-join alfter leaving with limit problem", func(t *testing.T) { + user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser1, _ := th.App.CreateUser(&user1) + user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser2, _ := th.App.CreateUser(&user2) + defer th.App.PermanentDeleteUser(&user1) + defer th.App.PermanentDeleteUser(&user2) + + th.App.joinUserToTeam(team, ruser1) + th.App.LeaveTeam(team, ruser1, ruser1.Id) + th.App.joinUserToTeam(team, ruser2) + if _, _, err := th.App.joinUserToTeam(team, ruser1); err == nil { + t.Fatal("Should fail") + } + }) +} diff --git a/i18n/en.json b/i18n/en.json index 4365a44fb..cecec7e1b 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3126,6 +3126,10 @@ "id": "api.websocket_handler.invalid_param.app_error", "translation": "Invalid {{.Name}} parameter" }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." + }, { "id": "app.channel.create_channel.no_team_id.app_error", "translation": "Must specify the team ID to create a channel" -- cgit v1.2.3-1-g7c22 From b8a4316b13bc0664648abda6b8d3de585d79173d Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 12 Feb 2018 11:09:51 -0500 Subject: ICU-753 Remove special behaviour for group messages in generic push notifications --- app/notification.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/notification.go b/app/notification.go index 1318308f8..2e99ca03c 100644 --- a/app/notification.go +++ b/app/notification.go @@ -607,7 +607,7 @@ func (a *App) sendPushNotification(post *model.Post, user *model.User, channel * if channel.Type == model.CHANNEL_DIRECT { msg.Category = model.CATEGORY_CAN_REPLY msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") - } else if wasMentioned || channel.Type == model.CHANNEL_GROUP { + } else if wasMentioned { msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention_no_channel") } else { msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention_no_channel") @@ -616,7 +616,7 @@ func (a *App) sendPushNotification(post *model.Post, user *model.User, channel * if channel.Type == model.CHANNEL_DIRECT { msg.Category = model.CATEGORY_CAN_REPLY msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") - } else if wasMentioned || channel.Type == model.CHANNEL_GROUP { + } else if wasMentioned { msg.Category = model.CATEGORY_CAN_REPLY msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName } else { -- cgit v1.2.3-1-g7c22 From c1b49f8b77e0e75afcc6cf4dc0f1c36569824151 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 12 Feb 2018 11:50:41 -0500 Subject: ICU-753 Added unit tests for push notification contents --- app/notification.go | 90 +++++++++++--------- app/notification_test.go | 211 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 39 deletions(-) diff --git a/app/notification.go b/app/notification.go index 2e99ca03c..83debe584 100644 --- a/app/notification.go +++ b/app/notification.go @@ -566,8 +566,6 @@ func (a *App) sendPushNotification(post *model.Post, user *model.User, channel * channelName = senderName } - userLocale := utils.GetUserTranslations(user.Locale) - msg := model.PushNotification{} if badge := <-a.Srv.Store.User().GetUnreadCount(user.Id); badge.Err != nil { msg.Badge = 1 @@ -596,44 +594,10 @@ func (a *App) sendPushNotification(post *model.Post, user *model.User, channel * msg.FromWebhook = fw } - if *a.Config().EmailSettings.PushNotificationContents == model.FULL_NOTIFICATION { - msg.Category = model.CATEGORY_CAN_REPLY - if channel.Type == model.CHANNEL_DIRECT { - msg.Message = senderName + ": " + model.ClearMentionTags(post.Message) - } else { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_in") + channelName + ": " + model.ClearMentionTags(post.Message) - } - } else if *a.Config().EmailSettings.PushNotificationContents == model.GENERIC_NO_CHANNEL_NOTIFICATION { - if channel.Type == model.CHANNEL_DIRECT { - msg.Category = model.CATEGORY_CAN_REPLY - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") - } else if wasMentioned { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention_no_channel") - } else { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention_no_channel") - } - } else { - if channel.Type == model.CHANNEL_DIRECT { - msg.Category = model.CATEGORY_CAN_REPLY - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") - } else if wasMentioned { - msg.Category = model.CATEGORY_CAN_REPLY - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName - } else { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention") + channelName - } - } - - // If the post only has images then push an appropriate message - if len(post.Message) == 0 && post.FileIds != nil && len(post.FileIds) > 0 { - if channel.Type == model.CHANNEL_DIRECT { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_image_only_dm") - } else { - msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_image_only") + channelName - } - } + userLocale := utils.GetUserTranslations(user.Locale) + hasFiles := post.FileIds != nil && len(post.FileIds) > 0 - //l4g.Debug("Sending push notification for user %v with msg of '%v'", user.Id, msg.Message) + msg.Message, msg.Category = a.getPushNotificationMessage(post.Message, wasMentioned, hasFiles, senderName, channelName, channel.Type, userLocale) for _, session := range sessions { tmpMessage := *model.PushNotificationFromJson(strings.NewReader(msg.ToJson())) @@ -655,6 +619,54 @@ func (a *App) sendPushNotification(post *model.Post, user *model.User, channel * return nil } +func (a *App) getPushNotificationMessage(postMessage string, wasMentioned bool, hasFiles bool, senderName string, channelName string, channelType string, userLocale i18n.TranslateFunc) (string, string) { + message := "" + category := "" + + if *a.Config().EmailSettings.PushNotificationContents == model.FULL_NOTIFICATION { + category = model.CATEGORY_CAN_REPLY + + if channelType == model.CHANNEL_DIRECT { + message = senderName + ": " + model.ClearMentionTags(postMessage) + } else { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_in") + channelName + ": " + model.ClearMentionTags(postMessage) + } + } else if *a.Config().EmailSettings.PushNotificationContents == model.GENERIC_NO_CHANNEL_NOTIFICATION { + if channelType == model.CHANNEL_DIRECT { + category = model.CATEGORY_CAN_REPLY + + message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") + } else if wasMentioned { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention_no_channel") + } else { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention_no_channel") + } + } else { + if channelType == model.CHANNEL_DIRECT { + category = model.CATEGORY_CAN_REPLY + + message = senderName + userLocale("api.post.send_notifications_and_forget.push_message") + } else if wasMentioned { + category = model.CATEGORY_CAN_REPLY + + message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName + } else { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_non_mention") + channelName + } + } + + // If the post only has images then push an appropriate message + if len(message) == 0 && hasFiles { + if channelType == model.CHANNEL_DIRECT { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_image_only_dm") + } else { + message = senderName + userLocale("api.post.send_notifications_and_forget.push_image_only") + channelName + } + } + + return message, category +} + func (a *App) ClearPushNotification(userId string, channelId string) { a.Go(func() { // Sleep is to allow the read replicas a chance to fully sync diff --git a/app/notification_test.go b/app/notification_test.go index 11f4df685..2b7b260c4 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -1166,3 +1166,214 @@ func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T) t.Fatal("Expected email text '" + teamURL + "'. Got " + body) } } + +func TestGetPushNotificationMessage(t *testing.T) { + th := Setup() + defer th.TearDown() + + for name, tc := range map[string]struct { + Message string + WasMentioned bool + HasFiles bool + Locale string + PushNotificationContents string + ChannelType string + + ExpectedMessage string + ExpectedCategory string + }{ + "full message, public channel, no mention": { + Message: "this is a message", + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, public channel, mention": { + Message: "this is a message", + WasMentioned: true, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, private channel, no mention": { + Message: "this is a message", + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, private channel, mention": { + Message: "this is a message", + WasMentioned: true, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, group message channel, no mention": { + Message: "this is a message", + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, group message channel, mention": { + Message: "this is a message", + WasMentioned: true, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user in channel: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, direct message channel, no mention": { + Message: "this is a message", + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "full message, direct message channel, mention": { + Message: "this is a message", + WasMentioned: true, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user: this is a message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message with channel, public channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user posted in channel", + }, + "generic message with channel, public channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user mentioned you in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message with channel, private channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user posted in channel", + }, + "generic message with channel, private channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user mentioned you in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message with channel, group message channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user posted in channel", + }, + "generic message with channel, group message channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user mentioned you in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message with channel, direct message channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user sent you a direct message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message with channel, direct message channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NOTIFICATION, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user sent you a direct message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message without channel, public channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user posted a message", + }, + "generic message without channel, public channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user mentioned you", + }, + "generic message without channel, private channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user posted a message", + }, + "generic message without channel, private channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user mentioned you", + }, + "generic message without channel, group message channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user posted a message", + }, + "generic message without channel, group message channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user mentioned you", + }, + "generic message without channel, direct message channel, no mention": { + Message: "this is a message", + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user sent you a direct message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "generic message without channel, direct message channel, mention": { + Message: "this is a message", + WasMentioned: true, + PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user sent you a direct message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + } { + t.Run(name, func(t *testing.T) { + locale := tc.Locale + if locale == "" { + locale = "en" + } + + pushNotificationContents := tc.PushNotificationContents + if pushNotificationContents == "" { + pushNotificationContents = model.FULL_NOTIFICATION + } + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.EmailSettings.PushNotificationContents = pushNotificationContents + }) + + if actualMessage, actualCategory := th.App.getPushNotificationMessage( + tc.Message, + tc.WasMentioned, + tc.HasFiles, + "user", + "channel", + tc.ChannelType, + utils.GetUserTranslations(locale), + ); actualMessage != tc.ExpectedMessage { + t.Fatalf("Received incorrect push notification message `%v`, expected `%v`", actualMessage, tc.ExpectedMessage) + } else if actualCategory != tc.ExpectedCategory { + t.Fatalf("Received incorrect push notification category `%v`, expected `%v`", actualCategory, tc.ExpectedCategory) + } + }) + } +} -- cgit v1.2.3-1-g7c22 From 3fef21e350737c235e6dfc2d9f35311d65290c3e Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 12 Feb 2018 12:56:46 -0500 Subject: ICU-753 Added unit tests for messages with only push notifications --- app/notification.go | 2 +- app/notification_test.go | 24 ++++++++++++++++++++++++ i18n/en.json | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/notification.go b/app/notification.go index 83debe584..8d8e72cf9 100644 --- a/app/notification.go +++ b/app/notification.go @@ -656,7 +656,7 @@ func (a *App) getPushNotificationMessage(postMessage string, wasMentioned bool, } // If the post only has images then push an appropriate message - if len(message) == 0 && hasFiles { + if len(postMessage) == 0 && hasFiles { if channelType == model.CHANNEL_DIRECT { message = senderName + userLocale("api.post.send_notifications_and_forget.push_image_only_dm") } else { diff --git a/app/notification_test.go b/app/notification_test.go index 2b7b260c4..cc501fbd0 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -1345,6 +1345,30 @@ func TestGetPushNotificationMessage(t *testing.T) { ExpectedMessage: "user sent you a direct message", ExpectedCategory: model.CATEGORY_CAN_REPLY, }, + "only files, public channel": { + HasFiles: true, + ChannelType: model.CHANNEL_OPEN, + ExpectedMessage: "user uploaded one or more files in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "only files, private channel": { + HasFiles: true, + ChannelType: model.CHANNEL_PRIVATE, + ExpectedMessage: "user uploaded one or more files in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "only files, group message channel": { + HasFiles: true, + ChannelType: model.CHANNEL_GROUP, + ExpectedMessage: "user uploaded one or more files in channel", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, + "only files, direct message channel": { + HasFiles: true, + ChannelType: model.CHANNEL_DIRECT, + ExpectedMessage: "user uploaded one or more files in a direct message", + ExpectedCategory: model.CATEGORY_CAN_REPLY, + }, } { t.Run(name, func(t *testing.T) { locale := tc.Locale diff --git a/i18n/en.json b/i18n/en.json index 4365a44fb..b31a6bd09 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1812,11 +1812,11 @@ }, { "id": "api.post.send_notifications_and_forget.push_image_only", - "translation": " Uploaded one or more files in " + "translation": " uploaded one or more files in " }, { "id": "api.post.send_notifications_and_forget.push_image_only_dm", - "translation": " Uploaded one or more files in a direct message" + "translation": " uploaded one or more files in a direct message" }, { "id": "api.post.send_notifications_and_forget.push_in", -- cgit v1.2.3-1-g7c22 From 8c22c5c6c6f835a6e73faf19036bad2a51bb9127 Mon Sep 17 00:00:00 2001 From: Jonathan Fritz Date: Tue, 13 Feb 2018 10:48:34 -0500 Subject: Renamed file to match existing scheme --- model/ChannelMemberHistoryResult.go | 15 --------------- model/channel_member_history_result.go | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 model/ChannelMemberHistoryResult.go create mode 100644 model/channel_member_history_result.go diff --git a/model/ChannelMemberHistoryResult.go b/model/ChannelMemberHistoryResult.go deleted file mode 100644 index ed3e79639..000000000 --- a/model/ChannelMemberHistoryResult.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package model - -type ChannelMemberHistoryResult struct { - ChannelId string - UserId string - JoinTime int64 - LeaveTime *int64 - - // these two fields are never set in the database - when we SELECT, we join on Users to get them - UserEmail string `db:"Email"` - Username string -} diff --git a/model/channel_member_history_result.go b/model/channel_member_history_result.go new file mode 100644 index 000000000..ed3e79639 --- /dev/null +++ b/model/channel_member_history_result.go @@ -0,0 +1,15 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +type ChannelMemberHistoryResult struct { + ChannelId string + UserId string + JoinTime int64 + LeaveTime *int64 + + // these two fields are never set in the database - when we SELECT, we join on Users to get them + UserEmail string `db:"Email"` + Username string +} -- cgit v1.2.3-1-g7c22 From 08c21f75199f959bbe63396be246e2b7d36a9a39 Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Tue, 13 Feb 2018 10:49:48 -0700 Subject: Added more tests and simplified code --- app/notification.go | 87 ++++++++++++++++++++++-------------------------- app/notification_test.go | 18 ++++++++++ 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/app/notification.go b/app/notification.go index 6531f72f7..90303fb8f 100644 --- a/app/notification.go +++ b/app/notification.go @@ -820,46 +820,54 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit } } + checkForMention := func(word string) bool { + isMention := false + + fmt.Printf("New Word: %v\n", word) + + if word == "@here" { + ret.HereMentioned = true + } + + if word == "@channel" { + ret.ChannelMentioned = true + } + + if word == "@all" { + ret.AllMentioned = true + } + + // Non-case-sensitive check for regular keys + if ids, match := keywords[strings.ToLower(word)]; match { + addMentionedUsers(ids) + isMention = true + } + + // Case-sensitive check for first name + if ids, match := keywords[word]; match { + addMentionedUsers(ids) + isMention = true + } + + return isMention + } processText := func(text string) { for _, word := range strings.FieldsFunc(text, func(c rune) bool { // Split on any whitespace or punctuation that can't be part of an at mention or emoji pattern return !(c == ':' || c == '.' || c == '-' || c == '_' || c == '@' || unicode.IsLetter(c) || unicode.IsNumber(c)) }) { - isMention := false - // skip word with format ':word:' with an assumption that it is an emoji format only if word[0] == ':' && word[len(word)-1] == ':' { continue } - // remove trailing '.', as that is the end of a sentence - word = strings.TrimSuffix(word, ".") - - if word == "@here" { - ret.HereMentioned = true - } - - if word == "@channel" { - ret.ChannelMentioned = true - } - - if word == "@all" { - ret.AllMentioned = true - } - - // Non-case-sensitive check for regular keys - if ids, match := keywords[strings.ToLower(word)]; match { - addMentionedUsers(ids) - isMention = true - } - - // Case-sensitive check for first name - if ids, match := keywords[word]; match { - addMentionedUsers(ids) - isMention = true + if checkForMention(word) { + continue } - if isMention { + // remove trailing '.', as that is the end of a sentence + word = strings.TrimSuffix(word, ".") + if checkForMention(word) { continue } @@ -870,27 +878,10 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit }) for _, splitWord := range splitWords { - if splitWord == "@here" { - ret.HereMentioned = true - } - - if splitWord == "@all" { - ret.AllMentioned = true - } - - if splitWord == "@channel" { - ret.ChannelMentioned = true - } - - // Non-case-sensitive check for regular keys - if ids, match := keywords[strings.ToLower(splitWord)]; match { - addMentionedUsers(ids) + if checkForMention(splitWord) { + continue } - - // Case-sensitive check for first name - if ids, match := keywords[splitWord]; match { - addMentionedUsers(ids) - } else if _, ok := systemMentions[splitWord]; !ok && strings.HasPrefix(splitWord, "@") { + if _, ok := systemMentions[splitWord]; !ok && strings.HasPrefix(splitWord, "@") { username := splitWord[1:] ret.OtherPotentialMentions = append(ret.OtherPotentialMentions, username) } diff --git a/app/notification_test.go b/app/notification_test.go index 61442c048..bd7da3db7 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -109,6 +109,24 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "OnePersonWithPeriodAtEndOfUsername": { + Message: "this is a message for @user.name.", + Keywords: map[string][]string{"@user.name.": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, + "OnePersonWithPeriodAtEndOfUsernameButNotSimilarName": { + Message: "this is a message for @user.name.", + Keywords: map[string][]string{"@user.name.": {id1}, "@user.name": {id2}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "OnePersonAtEndOfSentence": { Message: "this is a message for @user.", Keywords: map[string][]string{"@user": {id1}}, -- cgit v1.2.3-1-g7c22 From 1fe522659b0ecaa61d9c3d652ae2d89dd895248c Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Tue, 13 Feb 2018 11:51:38 -0700 Subject: remove debug statement --- app/notification.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/notification.go b/app/notification.go index 90303fb8f..7725445e4 100644 --- a/app/notification.go +++ b/app/notification.go @@ -823,8 +823,6 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit checkForMention := func(word string) bool { isMention := false - fmt.Printf("New Word: %v\n", word) - if word == "@here" { ret.HereMentioned = true } -- cgit v1.2.3-1-g7c22 From 2544ad70c392db2d859c98d582efad28ce59987d Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Tue, 13 Feb 2018 13:01:31 -0700 Subject: rerun jenkins? --- app/notification.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/notification.go b/app/notification.go index 7725445e4..30ce83360 100644 --- a/app/notification.go +++ b/app/notification.go @@ -849,6 +849,7 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit return isMention } + processText := func(text string) { for _, word := range strings.FieldsFunc(text, func(c rune) bool { // Split on any whitespace or punctuation that can't be part of an at mention or emoji pattern -- cgit v1.2.3-1-g7c22 From 69e56fc04237ae5a821a9d97c48bc830111d6c78 Mon Sep 17 00:00:00 2001 From: Stephen Kiers Date: Tue, 13 Feb 2018 13:20:46 -0700 Subject: gofmt --- app/notification.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/notification.go b/app/notification.go index 30ce83360..e158e08d5 100644 --- a/app/notification.go +++ b/app/notification.go @@ -819,7 +819,6 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit ret.MentionedUserIds[id] = true } } - checkForMention := func(word string) bool { isMention := false @@ -849,7 +848,6 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit return isMention } - processText := func(text string) { for _, word := range strings.FieldsFunc(text, func(c rune) bool { // Split on any whitespace or punctuation that can't be part of an at mention or emoji pattern -- cgit v1.2.3-1-g7c22 -- cgit v1.2.3-1-g7c22 From 7f93d17a5fb5e64a336c44c35b3a41a0c0047783 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Thu, 15 Feb 2018 02:04:21 +0000 Subject: translations PR 20180215 --- i18n/de.json | 6 +++++- i18n/en.json | 8 ++++---- i18n/es.json | 6 +++++- i18n/fr.json | 6 +++++- i18n/it.json | 6 +++++- i18n/ja.json | 6 +++++- i18n/ko.json | 10 +++++++--- i18n/nl.json | 36 +++++++++++++++++++--------------- i18n/pl.json | 6 +++++- i18n/pt-BR.json | 6 +++++- i18n/ru.json | 6 +++++- i18n/tr.json | 6 +++++- i18n/zh-CN.json | 60 ++++++++++++++++++++++++++++++--------------------------- i18n/zh-TW.json | 6 +++++- 14 files changed, 113 insertions(+), 61 deletions(-) diff --git a/i18n/de.json b/i18n/de.json index 4f9ac581f..bd722e4b3 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Der Einladungslink scheint nicht gültig zu sein" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins und/oder Plugin-Uploads wurden deaktiviert." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Dieses Team hat die maximale Anzahl erlaubter Konten erreicht. Kontaktieren Sie Ihren Systemadministrator, um eine höhere Begrenzung setzen zu lassen." + }, { "id": "app.user_access_token.disabled", "translation": "Persönliche Zugriffs-Token sind auf diesem Server deaktiviert. Bitte kontaktieren Sie ihren Systemadministrator für Details." diff --git a/i18n/en.json b/i18n/en.json index 3f5d0b4d3..ec4450ac8 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3126,10 +3126,6 @@ "id": "api.websocket_handler.invalid_param.app_error", "translation": "Invalid {{.Name}} parameter" }, - { - "id": "app.team.join_user_to_team.max_accounts.app_error", - "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." - }, { "id": "app.channel.create_channel.no_team_id.app_error", "translation": "Must specify the team ID to create a channel" @@ -3694,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins and/or plugin uploads have been disabled." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." + }, { "id": "app.user_access_token.disabled", "translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details." diff --git a/i18n/es.json b/i18n/es.json index b3d472b9f..b5f6a6489 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "El enlace de registro parece ser inválido" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Los Complementos y/o la carga de complementos han sido deshabilitados." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Este equipo ha alcanzado el número máximo de cuentas permitidas. Contacta a un administrador de sistema para que asigne un límite mayor." + }, { "id": "app.user_access_token.disabled", "translation": "Los tokens de acceso personal están inhabilitados en este servidor. Por favor, póngase en contacto con su administrador del sistema para obtener más detalles." diff --git a/i18n/fr.json b/i18n/fr.json index 66a414e64..60d17a2a9 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Le lien d'inscription semble ne pas être valide." }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Les plugins et/ou l'envoi de plugins ont été désactivés." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Cette équipe a atteint la limite du nombre maximum de comptes autorisés. Contactez votre administrateur système pour augmenter cette limite." + }, { "id": "app.user_access_token.disabled", "translation": "Les jetons d'accès personnel sont désactivés sur ce serveur. Veuillez contacter votre administrateur système pour plus d'informations." diff --git a/i18n/it.json b/i18n/it.json index c2f62ae5d..43a02369d 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Il collegamento per l'iscrizione non sembra essere valido" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "I plugin e/o il caricamento dei plugin è stato disattivato." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Questo gruppo ha raggiunto il limite massimo di utenti ammessi. Contatta il tuo amministratore di sistema per innalzare il limite." + }, { "id": "app.user_access_token.disabled", "translation": "I Token di accesso personale sono disattivati su questo server. Per favore contatta l'Amministratore di Sistema per ulteriori dettagli." diff --git a/i18n/ja.json b/i18n/ja.json index c525f471b..ac7ec2705 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "利用登録リンクが不正です" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "プラグインのアップロードは無効化されています。" }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "このチームは登録ユーザー数の上限に達しました。システム管理者に上限値の設定を変更するように依頼してください。" + }, { "id": "app.user_access_token.disabled", "translation": "このサーバーではパーソナルアクセストークンが無効になっています。詳しくはシステム管理者に問い合わせてください。" diff --git a/i18n/ko.json b/i18n/ko.json index 68fb33734..78fe29d16 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -1812,11 +1812,11 @@ }, { "id": "api.post.send_notifications_and_forget.push_image_only", - "translation": " Uploaded one or more files in " + "translation": " uploaded one or more files in " }, { "id": "api.post.send_notifications_and_forget.push_image_only_dm", - "translation": " Uploaded one or more files in a direct message" + "translation": " uploaded one or more files in a direct message" }, { "id": "api.post.send_notifications_and_forget.push_in", @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "유효하지 않은 가입 링크입니다." }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins and/or plugin uploads have been disabled." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." + }, { "id": "app.user_access_token.disabled", "translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details." diff --git a/i18n/nl.json b/i18n/nl.json index 2e02433e4..107434bca 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -1812,11 +1812,11 @@ }, { "id": "api.post.send_notifications_and_forget.push_image_only", - "translation": " Uploaded one or more files in " + "translation": " uploaded one or more files in " }, { "id": "api.post.send_notifications_and_forget.push_image_only_dm", - "translation": " Uploaded one or more files in a direct message" + "translation": " uploaded one or more files in a direct message" }, { "id": "api.post.send_notifications_and_forget.push_in", @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "De aanmeld link is niet geldig" }, { "id": "api.user.create_user.team_name.app_error", @@ -3208,11 +3208,11 @@ }, { "id": "app.import.import_line.null_direct_channel.error", - "translation": "Import data line has type \"direct_channel\" but the direct_channel object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.null_direct_post.error", - "translation": "Import data line has type \"direct_post\" but the direct_post object is null." + "translation": "Geimporteerde lijn met type \"user\", maar het \"user\" object is null." }, { "id": "app.import.import_line.null_post.error", @@ -3260,7 +3260,7 @@ }, { "id": "app.import.validate_channel_import_data.display_name_missing.error", - "translation": "Missing required channel property: display_name" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_channel_import_data.header_length.error", @@ -3284,7 +3284,7 @@ }, { "id": "app.import.validate_channel_import_data.team_missing.error", - "translation": "Missing required channel property: team" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_channel_import_data.type_invalid.error", @@ -3300,7 +3300,7 @@ }, { "id": "app.import.validate_direct_channel_import_data.members_required.error", - "translation": "Missing required direct channel property: members" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_direct_channel_import_data.members_too_few.error", @@ -3316,7 +3316,7 @@ }, { "id": "app.import.validate_direct_post_import_data.channel_members_required.error", - "translation": "Missing required direct post property: channel_members" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_direct_post_import_data.channel_members_too_few.error", @@ -3328,7 +3328,7 @@ }, { "id": "app.import.validate_direct_post_import_data.create_at_missing.error", - "translation": "Missing required direct post property: create_at" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_direct_post_import_data.create_at_zero.error", @@ -3340,7 +3340,7 @@ }, { "id": "app.import.validate_direct_post_import_data.message_missing.error", - "translation": "Missing required direct post property: message" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_direct_post_import_data.unknown_flagger.error", @@ -3348,7 +3348,7 @@ }, { "id": "app.import.validate_direct_post_import_data.user_missing.error", - "translation": "Missing required direct post property: user" + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_post_import_data.channel_missing.error", @@ -3356,7 +3356,7 @@ }, { "id": "app.import.validate_post_import_data.create_at_missing.error", - "translation": "Missing required Post property: create_at." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_post_import_data.create_at_zero.error", @@ -3384,7 +3384,7 @@ }, { "id": "app.import.validate_reaction_import_data.create_at_missing.error", - "translation": "Missing required Reaction property: create_at." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reaction_import_data.create_at_zero.error", @@ -3396,7 +3396,7 @@ }, { "id": "app.import.validate_reaction_import_data.emoji_name_missing.error", - "translation": "Missing required Reaction property: EmojiName." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reaction_import_data.user_missing.error", @@ -3408,7 +3408,7 @@ }, { "id": "app.import.validate_reply_import_data.create_at_missing.error", - "translation": "Missing required Reply property: create_at." + "translation": "Mist vereiste team kenmerk: naam." }, { "id": "app.import.validate_reply_import_data.create_at_zero.error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins and/or plugin uploads have been disabled." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Het maximaal aantal leden voor dit team is bereikt. Neem contact op met de beheerder voor een hoger limiet." + }, { "id": "app.user_access_token.disabled", "translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details." diff --git a/i18n/pl.json b/i18n/pl.json index d149f38b0..d2f26cf56 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Łącze rejestracji wydaje się być niepoprawne." }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins and/or plugin uploads have been disabled." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Ten zespół osiągnął limit kont. Skontaktuj się z administratorem aby ustanowić wyższy pułap." + }, { "id": "app.user_access_token.disabled", "translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details." diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 3ec45c2eb..072981d1f 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "O link de inscrição não parece ser válido" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins e/ou envio de plugin foi desabilitado." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Esta equipe alcançou o número máximo de contas permitidas. Contate o administrador do sistema para ajustar um limite maior." + }, { "id": "app.user_access_token.disabled", "translation": "Os tokens de acesso individual estão desativados neste servidor. Entre em contato com o administrador do sistema para obter detalhes." diff --git a/i18n/ru.json b/i18n/ru.json index cb4d26d45..b203bc482 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Неправильная ссылка на регистрацию" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Plugins and/or plugin uploads have been disabled." }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Эта команда достигла максимального количества разрешенных учетных записей. Свяжитесь с системным администратором для установки большего предела." + }, { "id": "app.user_access_token.disabled", "translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details." diff --git a/i18n/tr.json b/i18n/tr.json index ae782ddb4..2e159e1e8 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "Hesap açma bağlantısı geçersiz görünüyor" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "Uygulama ekleri ya da uygulama eki yüklemeleri devre dışı bırakılmış. " }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "Bu takım izin verilen en fazla hesap sayısına ulaşmış. Sınırı yükseltmesi için sistem yöneticinizle görüşün." + }, { "id": "app.user_access_token.disabled", "translation": "Bu sunucu üzerinde kişisel erişim kodları devre dışı bırakılmış. Lütfen ayrıntılı bilgi almak için sistem yöneticiniz ile görüşün." diff --git a/i18n/zh-CN.json b/i18n/zh-CN.json index 9186f936e..805670169 100644 --- a/i18n/zh-CN.json +++ b/i18n/zh-CN.json @@ -1162,7 +1162,7 @@ }, { "id": "api.emoji.delete.delete_reactions.app_error", - "translation": "无法删除表情符 %v 时删除反应" + "translation": "无法删除表情符 %v 时删除互动" }, { "id": "api.emoji.delete.permissions.app_error", @@ -1904,31 +1904,31 @@ }, { "id": "api.reaction.delete_reaction.mismatched_channel_id.app_error", - "translation": "因网址中频道 ID 与消息 ID不符而删除反应失败" + "translation": "因网址中频道 ID 与消息 ID不符而删除互动失败" }, { "id": "api.reaction.init.debug", - "translation": "正在初始化反应 API 路由" + "translation": "正在初始化互动 API 路由" }, { "id": "api.reaction.list_reactions.mismatched_channel_id.app_error", - "translation": "因网址中频道 ID 与消息 ID不符而获取反应失败" + "translation": "因网址中频道 ID 与消息 ID不符而获取互动失败" }, { "id": "api.reaction.save_reaction.invalid.app_error", - "translation": "无效反应。" + "translation": "无效互动。" }, { "id": "api.reaction.save_reaction.mismatched_channel_id.app_error", - "translation": "因网址中频道 ID 与消息 ID不符而保存反应失败" + "translation": "因网址中频道 ID 与消息 ID不符而保存互动失败" }, { "id": "api.reaction.save_reaction.user_id.app_error", - "translation": "您不能保存其他用户的反应。" + "translation": "您不能保存其他用户的互动。" }, { "id": "api.reaction.send_reaction_event.post.app_error", - "translation": "发送 websocket 反应事件时获取消息失败" + "translation": "发送 websocket 互动事件时获取消息失败" }, { "id": "api.saml.save_certificate.app_error", @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "注册链接无效" }, { "id": "api.user.create_user.team_name.app_error", @@ -3380,31 +3380,31 @@ }, { "id": "app.import.validate_reaction_import_data.create_at_before_parent.error", - "translation": "Reaction CreateAt property must be greater than the parent post CreateAt." + "translation": "互动 CreateAt 属性必须大于父消息 CreateAt。" }, { "id": "app.import.validate_reaction_import_data.create_at_missing.error", - "translation": "缺少反应必须属性:create_at。" + "translation": "缺少互动必须属性:create_at。" }, { "id": "app.import.validate_reaction_import_data.create_at_zero.error", - "translation": "反应 CreateAt 属性不能为零。" + "translation": "互动 CreateAt 属性不能为零。" }, { "id": "app.import.validate_reaction_import_data.emoji_name_length.error", - "translation": "反应 EmojiName 属性超过允许的最大长度。" + "translation": "互动 EmojiName 属性超过允许的最大长度。" }, { "id": "app.import.validate_reaction_import_data.emoji_name_missing.error", - "translation": "缺少反应必须属性:User。" + "translation": "缺少互动必须属性:User。" }, { "id": "app.import.validate_reaction_import_data.user_missing.error", - "translation": "缺少反应必须属性:User。" + "translation": "缺少互动必须属性:User。" }, { "id": "app.import.validate_reply_import_data.create_at_before_parent.error", - "translation": "Reply CreateAt property must be greater than the parent post CreateAt." + "translation": "回复 CreateAt 属性必须大于父消息 CreateAt。" }, { "id": "app.import.validate_reply_import_data.create_at_missing.error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "插件上传已禁用。" }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "这个团队已经达到允许的最大用户数量。请与系统管理员联系以设置更高的限制。" + }, { "id": "app.user_access_token.disabled", "translation": "个人访问令牌在本服务器禁用。请联系您的系统管理员了解详情。" @@ -4760,7 +4764,7 @@ }, { "id": "model.config.is_valid.group_unread_channels.app_error", - "translation": "Invalid group unread channels for service settings. Must be 'disabled', 'default_on', or 'default_off'." + "translation": "无效未读频道分组的服务设定。必须为 'disabled'、'default_on' 或 'default_off'。" }, { "id": "model.config.is_valid.image_proxy_type.app_error", @@ -6384,47 +6388,47 @@ }, { "id": "store.sql_reaction.delete.begin.app_error", - "translation": "删除反应时无法打开事务" + "translation": "删除互动时无法打开事务" }, { "id": "store.sql_reaction.delete.commit.app_error", - "translation": "删除反应时无法提交事务" + "translation": "删除互动时无法提交事务" }, { "id": "store.sql_reaction.delete.save.app_error", - "translation": "无法删除反应" + "translation": "无法删除互动" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.delete_reactions.app_error", - "translation": "无法用提供的表情符删除反应" + "translation": "无法用提供的表情符删除互动" }, { "id": "store.sql_reaction.delete_all_with_emoj_name.get_reactions.app_error", - "translation": "无法用提供的表情符获取反应" + "translation": "无法用提供的表情符获取互动" }, { "id": "store.sql_reaction.delete_all_with_emoji_name.update_post.warn", - "translation": "无法删除反应时更新 Post.HasReactions post_id=%v, error=%v" + "translation": "无法删除互动时更新 Post.HasReactions post_id=%v, error=%v" }, { "id": "store.sql_reaction.get_for_post.app_error", - "translation": "无法获取消息的反应" + "translation": "无法获取消息的互动" }, { "id": "store.sql_reaction.permanent_delete_batch.app_error", - "translation": "批量永久删除反应时遇到错误" + "translation": "批量永久删除互动时遇到错误" }, { "id": "store.sql_reaction.save.begin.app_error", - "translation": "无法保存反应时打开事务" + "translation": "无法保存互动时打开事务" }, { "id": "store.sql_reaction.save.commit.app_error", - "translation": "无法保存反应时提交事务" + "translation": "无法保存互动时提交事务" }, { "id": "store.sql_reaction.save.save.app_error", - "translation": "无法保存反应" + "translation": "无法保存互动" }, { "id": "store.sql_session.analytics_session_count.app_error", diff --git a/i18n/zh-TW.json b/i18n/zh-TW.json index e31a35941..eccb6138f 100644 --- a/i18n/zh-TW.json +++ b/i18n/zh-TW.json @@ -2708,7 +2708,7 @@ }, { "id": "api.user.create_user.signup_link_mismatched_invite_id.app_error", - "translation": "The signup link does not appear to be valid" + "translation": "此註冊連結不是有效連結" }, { "id": "api.user.create_user.team_name.app_error", @@ -3690,6 +3690,10 @@ "id": "app.plugin.upload_disabled.app_error", "translation": "模組 跟/或 上傳模組已被停用。" }, + { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "此團隊已達最大使用者數量上限。請聯絡系統管理員調大數量限制。" + }, { "id": "app.user_access_token.disabled", "translation": "個人存取 Token 在此伺服器被停用。詳情請洽管理員。" -- cgit v1.2.3-1-g7c22 From 98bd9a07538891d3ee9aded8865b4454cf72ea32 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 16 Feb 2018 17:03:12 -0500 Subject: Remove bad field from ChannelMemberHistory model --- model/channel_member_history.go | 1 - 1 file changed, 1 deletion(-) diff --git a/model/channel_member_history.go b/model/channel_member_history.go index bc71b580a..55435c320 100644 --- a/model/channel_member_history.go +++ b/model/channel_member_history.go @@ -6,7 +6,6 @@ package model type ChannelMemberHistory struct { ChannelId string UserId string - UserEmail string `db:"Email"` JoinTime int64 LeaveTime *int64 } -- cgit v1.2.3-1-g7c22 From 291432e2549d7f36c3c39336d925b036c0ef5de4 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 16 Feb 2018 17:14:22 -0500 Subject: Add upgrade code from 4.7.0 to 4.7.1 --- model/version.go | 1 + store/sqlstore/upgrade.go | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/model/version.go b/model/version.go index 1bd7baecc..6e461e5d5 100644 --- a/model/version.go +++ b/model/version.go @@ -13,6 +13,7 @@ import ( // It should be maitained in chronological order with most current // release at the front of the list. var versions = []string{ + "4.7.1", "4.7.0", "4.6.0", "4.5.0", diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index 75286d214..25c9e067a 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -15,6 +15,7 @@ import ( ) const ( + VERSION_4_7_1 = "4.7.1" VERSION_4_7_0 = "4.7.0" VERSION_4_6_0 = "4.6.0" VERSION_4_5_0 = "4.5.0" @@ -64,6 +65,7 @@ func UpgradeDatabase(sqlStore SqlStore) { UpgradeDatabaseToVersion45(sqlStore) UpgradeDatabaseToVersion46(sqlStore) UpgradeDatabaseToVersion47(sqlStore) + UpgradeDatabaseToVersion471(sqlStore) // If the SchemaVersion is empty this this is the first time it has ran // so lets set it to the current version. @@ -349,3 +351,13 @@ func UpgradeDatabaseToVersion47(sqlStore SqlStore) { saveSchemaVersion(sqlStore, VERSION_4_7_0) } } + +// If any new instances started with 4.7, they would have the bad Email column on the +// ChannelMemberHistory table. So for those cases we need to do an upgrade between +// 4.7.0 and 4.7.1 +func UpgradeDatabaseToVersion471(sqlStore SqlStore) { + if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) { + sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email") + saveSchemaVersion(sqlStore, VERSION_4_7_1) + } +} -- cgit v1.2.3-1-g7c22