Merge branch 'master' into advanced-permissions-phase-1

Этот коммит содержится в:
Martin Kraft
2018-03-23 09:08:49 -04:00
родитель 37f0e5e0eb 87762ae62e
Коммит 5fa1b35819
53 изменённых файлов: 2849 добавлений и 164 удалений

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

@@ -10,6 +10,7 @@ import (
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"time"
@@ -870,7 +871,7 @@ func TestGetInfoForFilename(t *testing.T) {
func readTestFile(name string) ([]byte, error) {
path, _ := utils.FindDir("tests")
file, err := os.Open(path + "/" + name)
file, err := os.Open(filepath.Join(path, name))
if err != nil {
return nil, err
}

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

@@ -1170,7 +1170,11 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
teamId := relayProps["team_id"]
if len(teamId) > 0 {
c.App.Go(func() {
c.App.AddDirectChannels(teamId, user)
if err := c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
l4g.Error(err.Error())
} else {
c.App.AddDirectChannels(teamId, user)
}
})
}
case model.OAUTH_ACTION_EMAIL_TO_SSO:

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

@@ -12,6 +12,7 @@ import (
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"time"
@@ -778,7 +779,7 @@ func TestUserUploadProfileImage(t *testing.T) {
}
path, _ := utils.FindDir("tests")
file, err := os.Open(path + "/test.png")
file, err := os.Open(filepath.Join(path, "test.png"))
if err != nil {
t.Fatal(err)
}

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

@@ -11,6 +11,7 @@ import (
"net"
"net/http"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
@@ -303,7 +304,11 @@ func (me *TestHelper) CreateUserWithClient(client *model.Client4) *model.User {
}
utils.DisableDebugLogForTest()
ruser, _ := client.CreateUser(user)
ruser, response := client.CreateUser(user)
if response.Error != nil {
panic(response.Error)
}
ruser.Password = "Password1"
store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
utils.EnableDebugLogForTest()
@@ -676,7 +681,7 @@ func CheckInternalErrorStatus(t *testing.T, resp *model.Response) {
func readTestFile(name string) ([]byte, error) {
path, _ := utils.FindDir("tests")
file, err := os.Open(path + "/" + name)
file, err := os.Open(filepath.Join(path, name))
if err != nil {
return nil, err
}

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

@@ -6,6 +6,7 @@ package api4
import (
"net/http"
"net/url"
"path/filepath"
"strings"
l4g "github.com/alecthomas/log4go"
@@ -375,7 +376,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
http.ServeFile(w, r, staticDir+"root.html")
http.ServeFile(w, r, filepath.Join(staticDir, "root.html"))
}
func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {

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

@@ -8,6 +8,7 @@ import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/mattermost/mattermost-server/model"
@@ -53,7 +54,7 @@ func TestPlugin(t *testing.T) {
}()
path, _ := utils.FindDir("tests")
file, err := os.Open(path + "/testplugin.tar.gz")
file, err := os.Open(filepath.Join(path, "testplugin.tar.gz"))
if err != nil {
t.Fatal(err)
}

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

@@ -17,6 +17,8 @@ import (
func (api *API) InitSystem() {
api.BaseRoutes.System.Handle("/ping", api.ApiHandler(getSystemPing)).Methods("GET")
api.BaseRoutes.System.Handle("/timezones", api.ApiSessionRequired(getSupportedTimezones)).Methods("GET")
api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(getConfig)).Methods("GET")
api.BaseRoutes.ApiRoot.Handle("/config", api.ApiSessionRequired(updateConfig)).Methods("PUT")
api.BaseRoutes.ApiRoot.Handle("/config/reload", api.ApiSessionRequired(configReload)).Methods("POST")
@@ -378,6 +380,18 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(rows.ToJson()))
}
func getSupportedTimezones(c *Context, w http.ResponseWriter, r *http.Request) {
supportedTimezones := c.App.Timezones()
if supportedTimezones != nil {
w.Write([]byte(model.TimezonesToJson(supportedTimezones)))
return
}
emptyTimezones := make([]string, 0)
w.Write([]byte(model.TimezonesToJson(emptyTimezones)))
}
func testS3(c *Context, w http.ResponseWriter, r *http.Request) {
cfg := model.ConfigFromJson(r.Body)
if cfg == nil {

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

@@ -527,3 +527,15 @@ func TestS3TestConnection(t *testing.T) {
t.Fatal("should return error ")
}
}
func TestSupportedTimezones(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
Client := th.Client
supportedTimezonesFromConfig := th.App.Timezones()
supportedTimezones, resp := Client.GetSupportedTimezone()
CheckNoError(t, resp)
assert.Equal(t, supportedTimezonesFromConfig, supportedTimezones)
}

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

@@ -285,7 +285,7 @@ func getTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if members, err := c.App.GetTeamMembers(c.Params.TeamId, c.Params.Page, c.Params.PerPage); err != nil {
if members, err := c.App.GetTeamMembers(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage); err != nil {
c.Err = err
return
} else {
@@ -543,9 +543,9 @@ func getAllTeams(c *Context, w http.ResponseWriter, r *http.Request) {
var err *model.AppError
if c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
teams, err = c.App.GetAllTeamsPage(c.Params.Page, c.Params.PerPage)
teams, err = c.App.GetAllTeamsPage(c.Params.Page*c.Params.PerPage, c.Params.PerPage)
} else {
teams, err = c.App.GetAllOpenTeamsPage(c.Params.Page, c.Params.PerPage)
teams, err = c.App.GetAllOpenTeamsPage(c.Params.Page*c.Params.PerPage, c.Params.PerPage)
}
if err != nil {

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

@@ -573,6 +573,10 @@ func TestGetAllTeams(t *testing.T) {
_, resp := Client.CreateTeam(team)
CheckNoError(t, resp)
team2 := &model.Team{DisplayName: "Name2", Name: GenerateTestTeamName(), Email: th.GenerateTestEmail(), Type: model.TEAM_OPEN, AllowOpenInvite: true}
_, resp = Client.CreateTeam(team2)
CheckNoError(t, resp)
rrteams, resp := Client.GetAllTeams("", 0, 1)
CheckNoError(t, resp)
@@ -617,6 +621,17 @@ func TestGetAllTeams(t *testing.T) {
t.Fatal("wrong number of teams - should be 0")
}
rrteams, resp = Client.GetAllTeams("", 0, 2)
CheckNoError(t, resp)
rrteams2, resp = Client.GetAllTeams("", 1, 2)
CheckNoError(t, resp)
for _, t1 := range rrteams {
for _, t2 := range rrteams2 {
assert.NotEqual(t, t1.Id, t2.Id, "different pages should not have the same teams")
}
}
Client.Logout()
_, resp = Client.GetAllTeams("", 1, 10)
CheckUnauthorizedStatus(t, resp)
@@ -1146,6 +1161,17 @@ func TestGetTeamMembers(t *testing.T) {
t.Fatal("should be no member")
}
rmembers, resp = Client.GetTeamMembers(team.Id, 0, 2, "")
CheckNoError(t, resp)
rmembers2, resp := Client.GetTeamMembers(team.Id, 1, 2, "")
CheckNoError(t, resp)
for _, tm1 := range rmembers {
for _, tm2 := range rmembers2 {
assert.NotEqual(t, tm1.UserId+tm1.TeamId, tm2.UserId+tm2.TeamId, "different pages should not have the same members")
}
}
_, resp = Client.GetTeamMembers("junk", 0, 100, "")
CheckBadRequestStatus(t, resp)

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

@@ -996,6 +996,10 @@ func TestPatchUser(t *testing.T) {
patch.Position = new(string)
patch.NotifyProps = model.StringMap{}
patch.NotifyProps["comment"] = "somethingrandom"
patch.Timezone = model.StringMap{}
patch.Timezone["useAutomaticTimezone"] = "true"
patch.Timezone["automaticTimezone"] = "America/New_York"
patch.Timezone["manualTimezone"] = ""
ruser, resp := Client.PatchUser(user.Id, patch)
CheckNoError(t, resp)
@@ -1019,6 +1023,15 @@ func TestPatchUser(t *testing.T) {
if ruser.NotifyProps["comment"] != "somethingrandom" {
t.Fatal("NotifyProps did not update properly")
}
if ruser.Timezone["useAutomaticTimezone"] != "true" {
t.Fatal("useAutomaticTimezone did not update properly")
}
if ruser.Timezone["automaticTimezone"] != "America/New_York" {
t.Fatal("automaticTimezone did not update properly")
}
if ruser.Timezone["manualTimezone"] != "" {
t.Fatal("manualTimezone did not update properly")
}
patch.Username = model.NewString(th.BasicUser2.Username)
_, resp = Client.PatchUser(user.Id, patch)

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

@@ -66,6 +66,8 @@ type App struct {
clientLicenseValue atomic.Value
licenseListeners map[string]func()
timezones atomic.Value
siteURL string
newStore func() store.Store
@@ -127,6 +129,9 @@ func New(options ...Option) (outApp *App, outErr error) {
return nil, err
}
app.EnableConfigWatch()
app.LoadTimezones()
if err := utils.InitTranslations(app.Config().LocalizationSettings); err != nil {
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
}
@@ -439,7 +444,11 @@ func (a *App) WaitForGoroutines() {
}
func (a *App) HTMLTemplates() *template.Template {
return a.htmlTemplateWatcher.Templates()
if a.htmlTemplateWatcher != nil {
return a.htmlTemplateWatcher.Templates()
}
return nil
}
func (a *App) HTTPClient(trustURLs bool) *http.Client {

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

@@ -7,6 +7,7 @@ import (
"bytes"
"io"
"os"
"path/filepath"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
@@ -43,7 +44,7 @@ func (cfg *AutoPostCreator) UploadTestFile() ([]string, bool) {
filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})]
path, _ := utils.FindDir("web/static/images")
file, err := os.Open(path + "/" + filename)
file, err := os.Open(filepath.Join(path, filename))
if err != nil {
return nil, false
}

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

@@ -54,6 +54,7 @@ func (a *App) LoadConfig(configFile string) *model.AppError {
a.configFile = configPath
utils.ConfigureLog(&cfg.LogSettings)
l4g.Info("Using config file at %s", configPath)
a.config.Store(cfg)

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

@@ -399,7 +399,7 @@ func (a *App) ImportChannel(data *ChannelImportData, dryRun bool) *model.AppErro
var team *model.Team
if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest)
} else {
team = result.Data.(*model.Team)
}
@@ -781,7 +781,7 @@ func (a *App) ImportUser(data *UserImportData, dryRun bool) *model.AppError {
if len(preferences) > 0 {
if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, "", http.StatusInternalServerError)
return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError)
}
}
@@ -899,7 +899,7 @@ func (a *App) ImportUserChannels(user *model.User, team *model.Team, teamMember
if len(preferences) > 0 {
if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, "", http.StatusInternalServerError)
return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError)
}
}
@@ -1069,7 +1069,7 @@ func (a *App) ImportReaction(data *ReactionImportData, post *model.Post, dryRun
var user *model.User
if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest)
} else {
user = result.Data.(*model.User)
}
@@ -1092,7 +1092,7 @@ func (a *App) ImportReply(data *ReplyImportData, post *model.Post, dryRun bool)
var user *model.User
if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest)
} else {
user = result.Data.(*model.User)
}
@@ -1147,21 +1147,21 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError {
var team *model.Team
if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest)
} else {
team = result.Data.(*model.Team)
}
var channel *model.Channel
if result := <-a.Srv.Store.Channel().GetByName(team.Id, *data.Channel, false); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, result.Err.Error(), http.StatusBadRequest)
} else {
channel = result.Data.(*model.Channel)
}
var user *model.User
if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, result.Err.Error(), http.StatusBadRequest)
} else {
user = result.Data.(*model.User)
}
@@ -1210,7 +1210,7 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError {
var user *model.User
if result := <-a.Srv.Store.User().GetByUsername(username); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, result.Err.Error(), http.StatusBadRequest)
} else {
user = result.Data.(*model.User)
}
@@ -1225,7 +1225,7 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError {
if len(preferences) > 0 {
if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, "", http.StatusInternalServerError)
return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError)
}
}
}
@@ -1351,7 +1351,7 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m
userIds = append(userIds, user.Id)
userMap[username] = user.Id
} else {
return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest)
}
}
@@ -1360,14 +1360,14 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m
if len(userIds) == 2 {
ch, err := a.createDirectChannel(userIds[0], userIds[1])
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
} else {
channel = ch
}
} else {
ch, err := a.createGroupChannel(userIds, userIds[0])
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
} else {
channel = ch
}
@@ -1403,7 +1403,7 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m
if data.Header != nil {
channel.Header = *data.Header
if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, result.Err.Error(), http.StatusBadRequest)
}
}
@@ -1461,7 +1461,7 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A
user := result.Data.(*model.User)
userIds = append(userIds, user.Id)
} else {
return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest)
}
}
@@ -1469,14 +1469,14 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A
if len(userIds) == 2 {
ch, err := a.createDirectChannel(userIds[0], userIds[1])
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
} else {
channel = ch
}
} else {
ch, err := a.createGroupChannel(userIds, userIds[0])
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, "", http.StatusBadRequest)
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
} else {
channel = ch
}
@@ -1548,7 +1548,7 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A
if len(preferences) > 0 {
if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil {
return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, "", http.StatusInternalServerError)
return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError)
}
}
}

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

@@ -4,6 +4,7 @@
package app
import (
"path/filepath"
"runtime/debug"
"strings"
"testing"
@@ -370,7 +371,7 @@ func TestImportValidateUserImportData(t *testing.T) {
// Test a valid User with all fields populated.
testsDir, _ := utils.FindDir("tests")
data = UserImportData{
ProfileImage: ptrStr(testsDir + "test.png"),
ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")),
Username: ptrStr("bob"),
Email: ptrStr("bob@example.com"),
AuthService: ptrStr("ldap"),
@@ -1471,7 +1472,7 @@ func TestImportImportUser(t *testing.T) {
username := model.NewId()
testsDir, _ := utils.FindDir("tests")
data = UserImportData{
ProfileImage: ptrStr(testsDir + "test.png"),
ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")),
Username: &username,
Email: ptrStr(model.NewId() + "@example.com"),
Nickname: ptrStr(model.NewId()),
@@ -1527,7 +1528,7 @@ func TestImportImportUser(t *testing.T) {
// Alter all the fields of that user.
data.Email = ptrStr(model.NewId() + "@example.com")
data.ProfileImage = ptrStr(testsDir + "testgif.gif")
data.ProfileImage = ptrStr(filepath.Join(testsDir, "testgif.gif"))
data.AuthService = ptrStr("ldap")
data.AuthData = &username
data.Nickname = ptrStr(model.NewId())

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

@@ -401,7 +401,7 @@ func (a *App) InitPlugins(pluginPath, webappPath string, supervisorOverride plug
options = append(options, pluginenv.SupervisorProvider(supervisorOverride))
} else if err := sandbox.CheckSupport(); err != nil {
l4g.Warn(err.Error())
l4g.Warn("plugin sandboxing is not supported. plugins will run with the same access level as the server")
l4g.Warn("plugin sandboxing is not supported. plugins will run with the same access level as the server. See documentation to learn more: https://developers.mattermost.com/extend/plugins/security/")
options = append(options, pluginenv.SupervisorProvider(rpcplugin.SupervisorProvider))
} else {
options = append(options, pluginenv.SupervisorProvider(sandbox.SupervisorProvider))

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

@@ -8,7 +8,6 @@ import (
"mime/multipart"
"net/http"
"os"
"path/filepath"
"github.com/mattermost/mattermost-server/model"
@@ -42,7 +41,7 @@ func WriteSamlFile(fileData *multipart.FileHeader) *model.AppError {
defer file.Close()
configDir, _ := utils.FindDir("config")
out, err := os.Create(configDir + filename)
out, err := os.Create(filepath.Join(configDir, filename))
if err != nil {
return model.NewAppError("AddSamlCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
}

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

@@ -225,7 +225,7 @@ func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
}
if result := <-a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); result.Err != nil {
l4g.Error(utils.T("api.status.last_activity.error"), session.UserId, session.Id)
l4g.Error(utils.T("api.status.last_activity.error"), session.UserId, session.Id, result.Err)
}
session.LastActivityAt = now

28
app/timezone.go Обычный файл
Просмотреть файл

@@ -0,0 +1,28 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package app
import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
)
func (a *App) Timezones() model.SupportedTimezones {
if cfg := a.timezones.Load(); cfg != nil {
return cfg.(model.SupportedTimezones)
}
return model.SupportedTimezones{}
}
func (a *App) LoadTimezones() {
timezonePath := "timezones.json"
if a.Config().TimezoneSettings.SupportedTimezonesPath != nil && len(*a.Config().TimezoneSettings.SupportedTimezonesPath) > 0 {
timezonePath = *a.Config().TimezoneSettings.SupportedTimezonesPath
}
timezoneCfg := utils.LoadTimezones(timezonePath)
a.timezones.Store(timezoneCfg)
}

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

@@ -18,6 +18,7 @@ import (
"io/ioutil"
"mime/multipart"
"net/http"
"path/filepath"
"strconv"
"strings"
@@ -717,7 +718,7 @@ func CreateProfileImage(username string, userId string, initialFont string) ([]b
initial := string(strings.ToUpper(username)[0])
fontDir, _ := utils.FindDir("fonts")
fontBytes, err := ioutil.ReadFile(fontDir + initialFont)
fontBytes, err := ioutil.ReadFile(filepath.Join(fontDir, initialFont))
if err != nil {
return nil, model.NewAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error(), http.StatusInternalServerError)
}

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

@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"encoding/json"
"github.com/mattermost/mattermost-server/cmd"
"github.com/mattermost/mattermost-server/utils"
)
@@ -26,6 +27,11 @@ func TestConfigFlag(t *testing.T) {
configPath := filepath.Join(dir, "foo.json")
require.NoError(t, ioutil.WriteFile(configPath, []byte(config.ToJson()), 0600))
timezones := utils.LoadTimezones("timezones.json")
tzConfigPath := filepath.Join(dir, "timezones.json")
timezoneData, _ := json.Marshal(timezones)
require.NoError(t, ioutil.WriteFile(tzConfigPath, timezoneData, 0600))
i18n, ok := utils.FindDir("i18n")
require.True(t, ok)
require.NoError(t, utils.CopyDir(i18n, filepath.Join(dir, "i18n")))

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

@@ -130,6 +130,7 @@ func bulkImportCmdF(command *cobra.Command, args []string) error {
if lineNumber != 0 {
cmd.CommandPrettyPrintln(fmt.Sprintf("Error occurred on data file line %v", lineNumber))
}
return err
} else {
if apply {
cmd.CommandPrettyPrintln("Finished Bulk Import.")

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

@@ -211,6 +211,9 @@
"AllowCustomThemes": true,
"AllowedThemes": []
},
"TimezoneSettings": {
"SupportedTimezonesPath": "timezones.json"
},
"GitLabSettings": {
"Enable": false,
"Secret": "",
@@ -282,6 +285,8 @@
"IdpUrl": "",
"IdpDescriptorUrl": "",
"AssertionConsumerServiceURL": "",
"ScopingIDPProviderId": "",
"ScopingIDPName": "",
"IdpCertificateFile": "",
"PublicCertificateFile": "",
"PrivateKeyFile": "",

596
config/timezones.json Обычный файл
Просмотреть файл

@@ -0,0 +1,596 @@
[
"Africa/Abidjan",
"Africa/Accra",
"Africa/Addis_Ababa",
"Africa/Algiers",
"Africa/Asmara",
"Africa/Asmera",
"Africa/Bamako",
"Africa/Bangui",
"Africa/Banjul",
"Africa/Bissau",
"Africa/Blantyre",
"Africa/Brazzaville",
"Africa/Bujumbura",
"Africa/Cairo",
"Africa/Casablanca",
"Africa/Ceuta",
"Africa/Conakry",
"Africa/Dakar",
"Africa/Dar_es_Salaam",
"Africa/Djibouti",
"Africa/Douala",
"Africa/El_Aaiun",
"Africa/Freetown",
"Africa/Gaborone",
"Africa/Harare",
"Africa/Johannesburg",
"Africa/Juba",
"Africa/Kampala",
"Africa/Khartoum",
"Africa/Kigali",
"Africa/Kinshasa",
"Africa/Lagos",
"Africa/Libreville",
"Africa/Lome",
"Africa/Luanda",
"Africa/Lubumbashi",
"Africa/Lusaka",
"Africa/Malabo",
"Africa/Maputo",
"Africa/Maseru",
"Africa/Mbabane",
"Africa/Mogadishu",
"Africa/Monrovia",
"Africa/Nairobi",
"Africa/Ndjamena",
"Africa/Niamey",
"Africa/Nouakchott",
"Africa/Ouagadougou",
"Africa/Porto-Novo",
"Africa/Sao_Tome",
"Africa/Timbuktu",
"Africa/Tripoli",
"Africa/Tunis",
"Africa/Windhoek",
"America/Adak",
"America/Anchorage",
"America/Anguilla",
"America/Antigua",
"America/Araguaina",
"America/Argentina/Buenos_Aires",
"America/Argentina/Catamarca",
"America/Argentina/ComodRivadavia",
"America/Argentina/Cordoba",
"America/Argentina/Jujuy",
"America/Argentina/La_Rioja",
"America/Argentina/Mendoza",
"America/Argentina/Rio_Gallegos",
"America/Argentina/Salta",
"America/Argentina/San_Juan",
"America/Argentina/San_Luis",
"America/Argentina/Tucuman",
"America/Argentina/Ushuaia",
"America/Aruba",
"America/Asuncion",
"America/Atikokan",
"America/Atka",
"America/Bahia",
"America/Bahia_Banderas",
"America/Barbados",
"America/Belem",
"America/Belize",
"America/Blanc-Sablon",
"America/Boa_Vista",
"America/Bogota",
"America/Boise",
"America/Buenos_Aires",
"America/Cambridge_Bay",
"America/Campo_Grande",
"America/Cancun",
"America/Caracas",
"America/Catamarca",
"America/Cayenne",
"America/Cayman",
"America/Chicago",
"America/Chihuahua",
"America/Coral_Harbour",
"America/Cordoba",
"America/Costa_Rica",
"America/Creston",
"America/Cuiaba",
"America/Curacao",
"America/Danmarkshavn",
"America/Dawson",
"America/Dawson_Creek",
"America/Denver",
"America/Detroit",
"America/Dominica",
"America/Edmonton",
"America/Eirunepe",
"America/El_Salvador",
"America/Ensenada",
"America/Fort_Nelson",
"America/Fort_Wayne",
"America/Fortaleza",
"America/Glace_Bay",
"America/Godthab",
"America/Goose_Bay",
"America/Grand_Turk",
"America/Grenada",
"America/Guadeloupe",
"America/Guatemala",
"America/Guayaquil",
"America/Guyana",
"America/Halifax",
"America/Havana",
"America/Hermosillo",
"America/Indiana/Indianapolis",
"America/Indiana/Knox",
"America/Indiana/Marengo",
"America/Indiana/Petersburg",
"America/Indiana/Tell_City",
"America/Indiana/Vevay",
"America/Indiana/Vincennes",
"America/Indiana/Winamac",
"America/Indianapolis",
"America/Inuvik",
"America/Iqaluit",
"America/Jamaica",
"America/Jujuy",
"America/Juneau",
"America/Kentucky/Louisville",
"America/Kentucky/Monticello",
"America/Knox_IN",
"America/Kralendijk",
"America/La_Paz",
"America/Lima",
"America/Los_Angeles",
"America/Louisville",
"America/Lower_Princes",
"America/Maceio",
"America/Managua",
"America/Manaus",
"America/Marigot",
"America/Martinique",
"America/Matamoros",
"America/Mazatlan",
"America/Mendoza",
"America/Menominee",
"America/Merida",
"America/Metlakatla",
"America/Mexico_City",
"America/Miquelon",
"America/Moncton",
"America/Monterrey",
"America/Montevideo",
"America/Montreal",
"America/Montserrat",
"America/Nassau",
"America/New_York",
"America/Nipigon",
"America/Nome",
"America/Noronha",
"America/North_Dakota/Beulah",
"America/North_Dakota/Center",
"America/North_Dakota/New_Salem",
"America/Ojinaga",
"America/Panama",
"America/Pangnirtung",
"America/Paramaribo",
"America/Phoenix",
"America/Port-au-Prince",
"America/Port_of_Spain",
"America/Porto_Acre",
"America/Porto_Velho",
"America/Puerto_Rico",
"America/Punta_Arenas",
"America/Rainy_River",
"America/Rankin_Inlet",
"America/Recife",
"America/Regina",
"America/Resolute",
"America/Rio_Branco",
"America/Rosario",
"America/Santa_Isabel",
"America/Santarem",
"America/Santiago",
"America/Santo_Domingo",
"America/Sao_Paulo",
"America/Scoresbysund",
"America/Shiprock",
"America/Sitka",
"America/St_Barthelemy",
"America/St_Johns",
"America/St_Kitts",
"America/St_Lucia",
"America/St_Thomas",
"America/St_Vincent",
"America/Swift_Current",
"America/Tegucigalpa",
"America/Thule",
"America/Thunder_Bay",
"America/Tijuana",
"America/Toronto",
"America/Tortola",
"America/Vancouver",
"America/Virgin",
"America/Whitehorse",
"America/Winnipeg",
"America/Yakutat",
"America/Yellowknife",
"Antarctica/Casey",
"Antarctica/Davis",
"Antarctica/DumontDUrville",
"Antarctica/Macquarie",
"Antarctica/Mawson",
"Antarctica/McMurdo",
"Antarctica/Palmer",
"Antarctica/Rothera",
"Antarctica/South_Pole",
"Antarctica/Syowa",
"Antarctica/Troll",
"Antarctica/Vostok",
"Arctic/Longyearbyen",
"Asia/Aden",
"Asia/Almaty",
"Asia/Amman",
"Asia/Anadyr",
"Asia/Aqtau",
"Asia/Aqtobe",
"Asia/Ashgabat",
"Asia/Ashkhabad",
"Asia/Atyrau",
"Asia/Baghdad",
"Asia/Bahrain",
"Asia/Baku",
"Asia/Bangkok",
"Asia/Barnaul",
"Asia/Beirut",
"Asia/Bishkek",
"Asia/Brunei",
"Asia/Calcutta",
"Asia/Chita",
"Asia/Choibalsan",
"Asia/Chongqing",
"Asia/Chungking",
"Asia/Colombo",
"Asia/Dacca",
"Asia/Damascus",
"Asia/Dhaka",
"Asia/Dili",
"Asia/Dubai",
"Asia/Dushanbe",
"Asia/Famagusta",
"Asia/Gaza",
"Asia/Harbin",
"Asia/Hebron",
"Asia/Ho_Chi_Minh",
"Asia/Hong_Kong",
"Asia/Hovd",
"Asia/Irkutsk",
"Asia/Istanbul",
"Asia/Jakarta",
"Asia/Jayapura",
"Asia/Jerusalem",
"Asia/Kabul",
"Asia/Kamchatka",
"Asia/Karachi",
"Asia/Kashgar",
"Asia/Kathmandu",
"Asia/Katmandu",
"Asia/Khandyga",
"Asia/Kolkata",
"Asia/Krasnoyarsk",
"Asia/Kuala_Lumpur",
"Asia/Kuching",
"Asia/Kuwait",
"Asia/Macao",
"Asia/Macau",
"Asia/Magadan",
"Asia/Makassar",
"Asia/Manila",
"Asia/Muscat",
"Asia/Nicosia",
"Asia/Novokuznetsk",
"Asia/Novosibirsk",
"Asia/Omsk",
"Asia/Oral",
"Asia/Phnom_Penh",
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
"Asia/Saigon",
"Asia/Sakhalin",
"Asia/Samarkand",
"Asia/Seoul",
"Asia/Shanghai",
"Asia/Singapore",
"Asia/Srednekolymsk",
"Asia/Taipei",
"Asia/Tashkent",
"Asia/Tbilisi",
"Asia/Tehran",
"Asia/Tel_Aviv",
"Asia/Thimbu",
"Asia/Thimphu",
"Asia/Tokyo",
"Asia/Tomsk",
"Asia/Ujung_Pandang",
"Asia/Ulaanbaatar",
"Asia/Ulan_Bator",
"Asia/Urumqi",
"Asia/Ust-Nera",
"Asia/Vientiane",
"Asia/Vladivostok",
"Asia/Yakutsk",
"Asia/Yangon",
"Asia/Yekaterinburg",
"Asia/Yerevan",
"Atlantic/Azores",
"Atlantic/Bermuda",
"Atlantic/Canary",
"Atlantic/Cape_Verde",
"Atlantic/Faeroe",
"Atlantic/Faroe",
"Atlantic/Jan_Mayen",
"Atlantic/Madeira",
"Atlantic/Reykjavik",
"Atlantic/South_Georgia",
"Atlantic/St_Helena",
"Atlantic/Stanley",
"Australia/ACT",
"Australia/Adelaide",
"Australia/Brisbane",
"Australia/Broken_Hill",
"Australia/Canberra",
"Australia/Currie",
"Australia/Darwin",
"Australia/Eucla",
"Australia/Hobart",
"Australia/LHI",
"Australia/Lindeman",
"Australia/Lord_Howe",
"Australia/Melbourne",
"Australia/NSW",
"Australia/North",
"Australia/Perth",
"Australia/Queensland",
"Australia/South",
"Australia/Sydney",
"Australia/Tasmania",
"Australia/Victoria",
"Australia/West",
"Australia/Yancowinna",
"Brazil/Acre",
"Brazil/DeNoronha",
"Brazil/East",
"Brazil/West",
"CET",
"CST6CDT",
"Canada/Atlantic",
"Canada/Central",
"Canada/East-Saskatchewan",
"Canada/Eastern",
"Canada/Mountain",
"Canada/Newfoundland",
"Canada/Pacific",
"Canada/Saskatchewan",
"Canada/Yukon",
"Chile/Continental",
"Chile/EasterIsland",
"Cuba",
"EET",
"EST",
"EST5EDT",
"Egypt",
"Eire",
"Etc/GMT",
"Etc/GMT+0",
"Etc/GMT+1",
"Etc/GMT+10",
"Etc/GMT+11",
"Etc/GMT+12",
"Etc/GMT+2",
"Etc/GMT+3",
"Etc/GMT+4",
"Etc/GMT+5",
"Etc/GMT+6",
"Etc/GMT+7",
"Etc/GMT+8",
"Etc/GMT+9",
"Etc/GMT-0",
"Etc/GMT-1",
"Etc/GMT-10",
"Etc/GMT-11",
"Etc/GMT-12",
"Etc/GMT-13",
"Etc/GMT-14",
"Etc/GMT-2",
"Etc/GMT-3",
"Etc/GMT-4",
"Etc/GMT-5",
"Etc/GMT-6",
"Etc/GMT-7",
"Etc/GMT-8",
"Etc/GMT-9",
"Etc/GMT0",
"Etc/Greenwich",
"Etc/UCT",
"Etc/UTC",
"Etc/Universal",
"Etc/Zulu",
"Europe/Amsterdam",
"Europe/Andorra",
"Europe/Astrakhan",
"Europe/Athens",
"Europe/Belfast",
"Europe/Belgrade",
"Europe/Berlin",
"Europe/Bratislava",
"Europe/Brussels",
"Europe/Bucharest",
"Europe/Budapest",
"Europe/Busingen",
"Europe/Chisinau",
"Europe/Copenhagen",
"Europe/Dublin",
"Europe/Gibraltar",
"Europe/Guernsey",
"Europe/Helsinki",
"Europe/Isle_of_Man",
"Europe/Istanbul",
"Europe/Jersey",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Kirov",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
"Europe/Luxembourg",
"Europe/Madrid",
"Europe/Malta",
"Europe/Mariehamn",
"Europe/Minsk",
"Europe/Monaco",
"Europe/Moscow",
"Europe/Nicosia",
"Europe/Oslo",
"Europe/Paris",
"Europe/Podgorica",
"Europe/Prague",
"Europe/Riga",
"Europe/Rome",
"Europe/Samara",
"Europe/San_Marino",
"Europe/Sarajevo",
"Europe/Saratov",
"Europe/Simferopol",
"Europe/Skopje",
"Europe/Sofia",
"Europe/Stockholm",
"Europe/Tallinn",
"Europe/Tirane",
"Europe/Tiraspol",
"Europe/Ulyanovsk",
"Europe/Uzhgorod",
"Europe/Vaduz",
"Europe/Vatican",
"Europe/Vienna",
"Europe/Vilnius",
"Europe/Volgograd",
"Europe/Warsaw",
"Europe/Zagreb",
"Europe/Zaporozhye",
"Europe/Zurich",
"Factory",
"GB",
"GB-Eire",
"GMT",
"GMT+0",
"GMT-0",
"GMT0",
"Greenwich",
"HST",
"Hongkong",
"Iceland",
"Indian/Antananarivo",
"Indian/Chagos",
"Indian/Christmas",
"Indian/Cocos",
"Indian/Comoro",
"Indian/Kerguelen",
"Indian/Mahe",
"Indian/Maldives",
"Indian/Mauritius",
"Indian/Mayotte",
"Indian/Reunion",
"Iran",
"Israel",
"Jamaica",
"Japan",
"Kwajalein",
"Libya",
"MET",
"MST",
"MST7MDT",
"Mexico/BajaNorte",
"Mexico/BajaSur",
"Mexico/General",
"NZ",
"NZ-CHAT",
"Navajo",
"PRC",
"PST8PDT",
"Pacific/Apia",
"Pacific/Auckland",
"Pacific/Bougainville",
"Pacific/Chatham",
"Pacific/Chuuk",
"Pacific/Easter",
"Pacific/Efate",
"Pacific/Enderbury",
"Pacific/Fakaofo",
"Pacific/Fiji",
"Pacific/Funafuti",
"Pacific/Galapagos",
"Pacific/Gambier",
"Pacific/Guadalcanal",
"Pacific/Guam",
"Pacific/Honolulu",
"Pacific/Johnston",
"Pacific/Kiritimati",
"Pacific/Kosrae",
"Pacific/Kwajalein",
"Pacific/Majuro",
"Pacific/Marquesas",
"Pacific/Midway",
"Pacific/Nauru",
"Pacific/Niue",
"Pacific/Norfolk",
"Pacific/Noumea",
"Pacific/Pago_Pago",
"Pacific/Palau",
"Pacific/Pitcairn",
"Pacific/Pohnpei",
"Pacific/Ponape",
"Pacific/Port_Moresby",
"Pacific/Rarotonga",
"Pacific/Saipan",
"Pacific/Samoa",
"Pacific/Tahiti",
"Pacific/Tarawa",
"Pacific/Tongatapu",
"Pacific/Truk",
"Pacific/Wake",
"Pacific/Wallis",
"Pacific/Yap",
"Poland",
"Portugal",
"ROC",
"ROK",
"Singapore",
"Turkey",
"UCT",
"US/Alaska",
"US/Aleutian",
"US/Arizona",
"US/Central",
"US/East-Indiana",
"US/Eastern",
"US/Hawaii",
"US/Indiana-Starke",
"US/Michigan",
"US/Mountain",
"US/Pacific",
"US/Pacific-New",
"US/Samoa",
"UTC",
"Universal",
"W-SU",
"WET",
"Zulu"
]

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - E-Mail-Einstellungen überprüfen"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3-Bucket wird benötigt"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3-Endpunkt wird benötigt"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3-Region wird benötigt"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Leeres Array unterhalb von 'image' in der Anfrage"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v wurde aus dem Team entfernt."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Leeres Array unterhalb von 'image' in der Anfrage"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Keine Datei unter 'image' in der Anfrage"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Konnte Bild nicht öffnen"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Kann Multipart-Formular nicht analysieren"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Die Datei kann nicht hochgeladen werden. Ein Foto Speicherort ist nicht eingerichtet."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Bildupload nicht möglich. Datei ist zu groß."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Team-Anmeldung mit einer E-Mail-Adresse ist deaktiviert."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Kann extrahiertes Plugin nicht aktivieren. Plugin könnte schon existieren und aktiviert sein."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Fehler beim Speichern des Plugin-Status in der Konfiguration"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "'ExportFormat' des Nachrichten-Export-Jobs muss 'actiance' oder 'globalrelay' sein."
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "'ExportFormat' des Nachrichten-Export-Jobs muss 'actiance' oder 'globalrelay' sein."
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Nachrichten-Export-Aufgabe \"FileLocation\" muss ein beschreibbares Verzeichnis sein in welches die Exportdaten geschrieben werden"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Nachrichten-Export-Aufgabe \"FileLocation\" muss ein Unterverzeichnis von \"FileSettings.Directory\" sein"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Nachrichten-Export-Job GlobalRelayEmailAddress muss eine gültige E-Mail-Adresse sein."
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Nachrichten-Export-Job GlobalRelayEmailAddress muss eine gültige E-Mail-Adresse sein."

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

@@ -115,14 +115,14 @@
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Empty array under 'image' in request"
@@ -2202,50 +2202,6 @@
"id": "api.system.go_routines",
"translation": "The number of running goroutines is over the health threshold %v of %v"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Unable to upload team icon. Image storage is not configured."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Unable to upload team icon. File is too large."
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Could not parse multipart form"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "No file under 'image' in request"
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Empty array under 'image' in request"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Could not open image file"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.add_user_to_team.added",
"translation": "%v added to the team by %v."
@@ -2390,6 +2346,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v removed from the team."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Empty array under 'image' in request"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "No file under 'image' in request"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Could not open image file"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Could not parse multipart form"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Unable to upload team icon. Image storage is not configured."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Unable to upload team icon. File is too large."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Team sign-up with email is disabled."
@@ -3714,14 +3714,14 @@
"id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
},
{
"id": "app.plugin.deactivate.app_error",
"translation": "Unable to deactivate plugin"
@@ -3782,6 +3782,18 @@
"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.timezones.failed_deserialize.app_error",
"translation": "Failed to deserialize Timezone config file={{.Filename}}, err={{.Error}}"
},
{
"id": "app.timezones.load_config.app_error",
"translation": "Timezone config file does not exists file={{.Filename}}"
},
{
"id": "app.timezones.read_config.app_error",
"translation": "Failed to read Timezone config file={{.Filename}}, err={{.Error}}"
},
{
"id": "app.user_access_token.disabled",
"translation": "Personal access tokens are disabled on this server. Please contact your system administrator for details."
@@ -4962,30 +4974,6 @@
"id": "model.config.is_valid.message_export.batch_size.app_error",
"translation": "Message export job BatchSize must be a positive integer"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.daily_runtime.app_error",
"translation": "Message export job DailyRuntime must be a 24-hour time stamp in the form HH:MM."
@@ -5002,6 +4990,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Message export job FileLocation must be a writable directory that export data will be written to"
@@ -5010,6 +5002,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Message export job FileLocation must be a sub-directory of FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Configuración de pruebas de correo"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket es necesario"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint es necesario"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Región es necesaria"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Arreglo vacio bajo 'image' en la solicitud"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v removido del equipo."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Arreglo vacío bajo 'image' en la solicitud"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "No se pudo descodificar el icono de equipo"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "No se pudo descodificar la metadata del icono de equipo"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "No se pudo codificar el icono de equipo"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "Ocurrió un error al obtener el equipo"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "No hay un archivo bajo 'image' en la solicitud"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "No se pudo abrir el archivo de imagen"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "No se pudo analizar el formulario multipart"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "No se puede cargar el icono del equipo. El almacenamiento de imágenes no está configurado."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "No se pudo subir el icono del equipo. El archivo es demasiado grande."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "No se pudo guardar el icono del equipo"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "El registro a equipos por correo electrónico está inhabilitado."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "No se puede activar el plugin extraído. Puede que el plugin ya exista y esté activo."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "La configuración de plugin en tu archivo config.json debe ser actualizado manualmente cuando se utiliza ReadOnlyConfig con el agrupamiento de servidores habilitado."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error al guardar el estado del plugin en la configuración"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "El trabajo de exportación de Mensaje ExportFormat debe ser 'actiance' o 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "El trabajo de exportación de Mensaje ExportFormat debe ser 'actiance' o 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "El ajuste FileLocation para realizar el trabajo de Exportación de Mensajes debe ser un directorio con permiso de escritura donde la data de exportación será almacenada."
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "El ajuste FileLocation para realizar el trabajo de Exportación de Mensajes debe ser un sub-directorio de FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "El trabajo de exportación de mensajes ExportFormat está asignado a 'globalrelay', pero falta establecer los parámetros de GlobalRelaySettings"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "El parámetro de exportación de mensajes GlobalRelaySettings.CustomerType debe ser establecido en 'A9' o 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "El parámetro de exportación de mensajes GlobalRelaySettings.EmailAddress debe estar asignado a una dirección de correo electrónico válida"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "El parámetro de exportación de mensajes GlobalRelaySettings.SmtpPassword debe estar asignado"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "El parámetro de exportación de mensajes GlobalRelaySettings.SmtpUsername debe estar asignado"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "El trabajo de exportación de Mensaje GlobalRelayEmailAddress debe estar asignado a una dirección de correo electrónico válido."

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Test des paramètres e-mail"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Aucune image transmise dans la requête"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v a été retiré de l'équipe."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Aucune image transmise dans la requête"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Pas de fichier dans le paramètre \"image\" de la requête"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Impossible d'ouvrir le fichier image"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Impossible d'analyser le formulaire multipart"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Impossible d'envoyer le fichier. Le stockage d'images n'est pas configuré."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Impossible d'envoyer le fichier. Le fichier est trop volumineux."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "L'inscription avec une adresse e-mail est désactivée."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Impossible d'activer le plugin extrait. Il se peut qu'il existe déjà et soit déjà activé."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Une erreur s'est produite lors de la sauvegarde de l'état du plugin dans la configuration"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Le paramètre FileLocation de la tâche d'exportation de messages doit être un dossier avec droits d'écriture. Il s'agit du dossier dans lequel les données seront exportées."
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Le paramètre FileLocation de la tâche d'exportation de messages doit être un sous-dossier de FileSettings.Directory."
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Test delle impostazioni Email"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "Bucket S3 richiesto"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "Endpoint S3 richiesto"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "Region S3 richiesta"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Lista vuota per il campo 'image' nella richiesta"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v è stato rimosso dal gruppo."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "La richiesta contiene una lista vuota nel campo 'image'"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Impossibile decodificare l'icona del gruppo"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Impossibile decodificare i metadati dell'icona del gruppo"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Impossibile codificare l'icona del gruppo"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "Si è verificato un errore recuperando il gruppo"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "La richiesta non contiene file nel campo 'image'"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Impossibile aprire il file immagine"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Errore durante l'analisi della form multipart"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Impossibile caricare l'icona del gruppo. Lo spazio di archiviazione delle immagini non è configurato."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Impossibile caricare l'icona del gruppo. Il file è troppo grande."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Impossibile salvare l'icona del gruppo"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "L'iscrizione al gruppo con email è disabilitata."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Impossibile attivare il plugin estratto. Il plugin può essere già disponibile e dev'essere attivato."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Errore durante il salvataggio della configurazione del plugin"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "ExportFormat del lavoro di esportazione messaggi deve essere 'actianve' oppure 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "ExportFormat del lavoro di esportazione messaggi deve essere 'actianve' oppure 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Lavoro esportazione messaggi il valore FileLocation deve essere una cartella accessibile in scrittura in cui verranno salvati i dati esportati"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Lavoro esportazione messaggi il valore FileLocation deve essere una sottocartella di FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "GlobalRelayEmailAddress del lavoro di esportazione messaggi deve essere un indirizzo email valido"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "GlobalRelayEmailAddress del lavoro di esportazione messaggi deve essere un indirizzo email valido"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - 電子メール設定のテスト"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3バケット名が必要です"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3エンドポイントが必要です"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3リージョンが必要です"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "リクエストの'image'以下の配列が空です"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v はチームから削除されました。"
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "リクエストの'image'以下の配列が空です"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "チームアイコンをデコードできませんでした"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "チームアイコンメタデータをデコードできませんでした"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "チームアイコンをエンコードできませんでした"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "チームの取得中にエラーが発生しました"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "リクエストの'image'以下にファイルがありません"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "画像ファイルを開けません"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "マルチパートフォームを解析できませんでした"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "チームアイコンをアップロードできません。画像ストレージが設定されていません。"
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "チームアイコンをアップロードできません。ファイルが大き過ぎます。"
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "チームアイコンを保存できませんでした"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "電子メールによるチームへの利用登録は無効です。"
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "抽出されたプラグインを有効化できませんでした。プラグインが既に存在し、有効化されている可能性があります。"
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "クラスター化を有効にするとともにReadOnlyConfigを使用する際は、config.jsonファイルのプラグイン設定は手動で更新する必要があります。"
},
{
"id": "app.plugin.config.app_error",
"translation": "設定にプラグインの状態を保存する際にエラーが発生しました"
@@ -4144,7 +4204,7 @@
},
{
"id": "ent.metrics.stopping.info",
"translation": "メトリクスとプロファイリングのサーバーは%vで停止しています"
"translation": "%v のメトリクスとプロファイリングのサーバーは停止しています"
},
{
"id": "ent.mfa.activate.authenticate.app_error",
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "メッセージエクスポート処理の ExportFormat は 'actiance' か 'globalrelay' のいずれかでなくてはなりません"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "メッセージエクスポート処理の ExportFormat は 'actiance' か 'globalrelay' のいずれかでなくてはなりません"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "メッセーエクスポート処理の FileLocation はエクスポートデータが書き込まれる書き込み可能なディレクトリでなくてはなりません"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "メッセージエクスポート処理の FileLocation は FileSettings.Directory のサブディレクトリでなくてはなりません"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "メッセージエクスポート処理のExportFormatは 'globalrelay' に設定されていますが、GlobalRealySettingsが見つかりません。"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "メッセージエクスポートのGlobalRelaySettings.CustomerTypeには 'A9' か 'A10' のいずれかを設定してください。"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "メッセージエクスポート処理の GlobalRelay.EmailAddress には有効な電子メールアドレスが設定されていなくてはなりません"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "メッセージエクスポート処理のGlobalRelaySettings.SmtpPasswordが設定されていなければなりません。"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "メッセージエクスポート処理のGlobalRelaySettings.SmtpUsernameが設定されていなくてはなりません。"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "メッセージエクスポート処理の GlobalRelayEmailAddress には有効な電子メールアドレスが設定されていなくてはなりません"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - 이메일 설정 테스트중"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "요청의 'image' 속성에 빈 배열이 전달되었습니다"
@@ -641,7 +653,7 @@
},
{
"id": "api.command_dnd.desc",
"translation": "Do not disturb disables desktop and mobile push notifications."
"translation": "방해 금지모드는 데스크탑과 모바일 푸시 알림을 비활성화합니다."
},
{
"id": "api.command_dnd.disabled",
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v 가 채널에서 제거되었습니다."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "요청의 'image' 속성에 빈 배열이 전달되었습니다"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "요청의 'image' 속성 아래에 파일이 없습니다"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "이미지 파일을 열 수 없습니다."
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "잘못된 multipart form을 파싱할 수 없습니다."
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "파일을 업로드할 수 없습니다. 이미지 저장소가 설정되지 않았습니다."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "이미지 파일을 불러올 수 없습니다. 파일이 너무 큽니다."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "이메일을 통한 팀 가입이 비활성화 되어있습니다."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Message export job FileLocation must be a writable directory that export data will be written to"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Message export job FileLocation must be a sub-directory of FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - E-mail-instellingen testen"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Lege array bij 'image' in aanvraag"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v was verwijdert van het kanaal."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Lege array bij 'image' in aanvraag"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Geen bestand bij 'image' in aanvraag"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Kan licentie bestand niet openen"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Kan het 'multipart'-formulier niet verwerken"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Kan bestand niet uploaden. Afbeeldings opslag is niet geconfigureerd."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Kan bestand niet uploaden. Bestand is te groot."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Team aanmelding via e-mail is uitgeschakeld."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Message export job FileLocation must be a writable directory that export data will be written to"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Message export job FileLocation must be a sub-directory of FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Testowanie ustawień e-mail"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Pusta tablica w kluczu 'image' w żądaniu"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v został usunięty z zespołu."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Pusta tablica w kluczu 'image' w żądaniu"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Brak pliku w polu 'image' w żądaniu"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Nie można otworzyć pliku obrazu"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Nie udało się przetworzyć wieloczęściowego formularza"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Nie można wgrać pliku. Przechowywanie obrazów nie jest skonfigurowane."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Nie można wgrać pliku obrazu. Plik jest zbyt duży."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Zapisy do zespołu za pomocą email są wyłączone."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Message export job FileLocation must be a writable directory that export data will be written to"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Message export job FileLocation must be a sub-directory of FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Teste de Configurações de Email"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket é obrigatório"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint é obrigatório"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region é obrigatório"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Matriz vazia em 'image' na requisição"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v foi removido da equipe."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Matriz vazia em 'image' na requisição"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Não foi possível ler o ícone da equipe"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Não foi possível ler os metadados do ícone da equipe"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Não foi possível codificar o ícone da equipe"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "Ocorreu um erro ao obter a equipe"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Nenhum arquivo em 'image' na requisição"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Não foi possível abrir arquivo de imagem"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Não foi possível processar o formulário multipart"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Não é possível enviar o ícone para equipe. Armazenamento de imagem não está configurado."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Não é possível enviar o ícone para equipe. Arquivo muito grande."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Inscrição com e-mail na equipe está desativado."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Não foi possível ativar o plugin extraído. O plugin já pode existir e estar ativado."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Falha ao salvar o estado do plugin na configuração"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Na tarefa de exportação de mensagens o ExportFormat deve ser 'actiance' ou 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Na tarefa de exportação de mensagens o ExportFormat deve ser 'actiance' ou 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Trabalho de exportação de mensagens FileLocation deve ser um diretório gravável onde os dados de exportação serão gravados"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Trabalho de exportação de mensagens FileLocation deve ser um subdiretório de FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Na tarefa de exportação de mensagens o GlobalRelaySettings.EmailAddress deve ser um endereço de email válido"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Na tarefa de exportação de mensagens o GlobalRelayEmailAddress deve ser um endereço de email válido"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - Тестирование настроек электронной почты"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "Пустой массив 'image' в запросе"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": " %v удален из команды."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "Пустой массив 'image' в запросе"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "Нет файла 'image' в запросе"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Не могу открыть файл изображения"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Невозможно обработать форму из нескольких частей"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Не удалось загрузить файл. Хранилище изображений не настроено."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Невозможно загрузить изображение. Файл слишком большой."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "Вход в команду с электронной почтой отключен."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "Error saving plugin state in config"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "Message export job ExportFormat must be one of either 'actiance' or 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "Message export job FileLocation must be a writable directory that export data will be written to"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "Message export job FileLocation must be a sub-directory of FileSettings.Directory"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "Message export job GlobalRelaySettings.EmailAddress must be set to a valid email address"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "Message export job GlobalRelayEmailAddress must be set to a valid email address"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - E-posta Ayarları Sınanıyor"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Buketi zorunludur"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Bitiş Noktası zorunludur"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Bölgesi zorunludur"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "İstekte 'görsel' altında boş dizi"
@@ -629,7 +641,7 @@
},
{
"id": "api.command_collapse.desc",
"translation": "Görsel önizlemeleri otomatik daraltılsın"
"translation": "Görsel ön izlemeleri otomatik daraltılsın"
},
{
"id": "api.command_collapse.name",
@@ -689,7 +701,7 @@
},
{
"id": "api.command_expand.desc",
"translation": "Görsel önizlemesi otomatik daraltılmasın"
"translation": "Görsel ön izlemeleri otomatik daraltılmasın"
},
{
"id": "api.command_expand.name",
@@ -701,7 +713,7 @@
},
{
"id": "api.command_expand_collapse.fail.app_error",
"translation": "Önizlemeler genişletilirken bir sorun çıktı"
"translation": "Ön izlemeler genişletilirken bir sorun çıktı"
},
{
"id": "api.command_groupmsg.desc",
@@ -1222,7 +1234,7 @@
},
{
"id": "api.file.get_file_preview.no_preview.app_error",
"translation": "Dosyanın önizleme görseli yok"
"translation": "Dosyanın ön izleme görseli yok"
},
{
"id": "api.file.get_file_thumbnail.no_thumbnail.app_error",
@@ -1262,11 +1274,11 @@
},
{
"id": "api.file.handle_images_forget.encode_preview.error",
"translation": "Görsel JPG önizlemesi olarak kodlanamadı. Yol: %v Hata: %v"
"translation": "Görsel JPG ön izlemesi olarak kodlanamadı. Yol: %v Hata: %v"
},
{
"id": "api.file.handle_images_forget.upload_preview.error",
"translation": "Önizleme yüklenemedi. Yol: %v Hata: %v"
"translation": "Ön izleme yüklenemedi. Yol: %v Hata: %v"
},
{
"id": "api.file.handle_images_forget.upload_thumb.error",
@@ -1768,7 +1780,7 @@
},
{
"id": "api.post.link_preview_disabled.app_error",
"translation": "Bağlantı önizleme özelliği sistem yöneticisi tarafından devre dışı bırakılmış."
"translation": "Bağlantı ön izleme özelliği sistem yöneticisi tarafından devre dışı bırakılmış."
},
{
"id": "api.post.make_direct_channel_visible.get_2_members.error",
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v takımdan çıkarıldı."
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "İstekte 'görsel' altındaki dizi boş"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Takım simgesinin kodu çözülemedi"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Takım simgesi üst verisinin kodu çözülemedi"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Takım simgesi kodlanamadı"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "Takım alınırken bir sorun çıktı"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "İstekte 'görsel' altında dosya yok"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "Görsel dosyasıılamadı"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "Çok parçalı form işlenemedi"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "Takım simgesi yüklenemedi. Görsel deposu ayarları yapılmamış."
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "Takım simgesi yüklenemedi. Dosya çok büyük."
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Takım simgesi kaydedilemedi"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "E-posta ile takım hesabı açma özelliği devre dışı bırakılmış."
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "Ayıklanan uygulama eki etkinleştirilemedi. Uygulama eki zaten var ve etkinleştirilmiş olabilir."
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "Küme özelliği kullanılırken ve SaltOkunurYapılandırma seçeneği etkinken config.json dosyasındaki uygulama eki yapılandırması el ile güncellenmelidir"
},
{
"id": "app.plugin.config.app_error",
"translation": "Uygulama eki durumu yapılandırmaya kaydedilirken sorun çıktı"
@@ -4764,11 +4824,11 @@
},
{
"id": "model.config.is_valid.file_preview_height.app_error",
"translation": "Önizleme yüksekliği dosya ayarı geçersiz. Sıfır ya da pozitif bir sayı olmalı."
"translation": "Ön izleme yüksekliği dosya ayarı geçersiz. Sıfır ya da pozitif bir sayı olmalı."
},
{
"id": "model.config.is_valid.file_preview_width.app_error",
"translation": "Önizleme genişliği dosya ayarı geçersiz. Sıfır ya da pozitif bir sayı olmalı."
"translation": "Ön izleme genişliği dosya ayarı geçersiz. Sıfır ya da pozitif bir sayı olmalı."
},
{
"id": "model.config.is_valid.file_profile_height.app_error",
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "İleti dışa aktarma görevinin Dışa Aktarma Biçimi 'actiance' ya da 'genelaktarım' olmalıdır"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "İleti dışa aktarma görevinin Dışa Aktarma Biçimi 'actiance' ya da 'genelaktarım' olmalıdır"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "İleti dışa aktarma görevi DosyaKonumu değeri dışa aktarılacak verilerin kaydedilebilmesi için yazılabilen bir klasör olmalıdır"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "İleti dışa aktarma görevi DosyaKonumu DosyaAyarları.Klasör değerinin bir alt klasörü olmalıdır"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "İleti dışa aktarma görevi DışaAktarmaBiçimi 'GenelAktarıcı' olarak ayarlanmış ancak GenelAktarıcıAyarları eksik"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "İleti dışa aktarma görevi GenelAktarıcıAyarları.MüşteriTürü 'A9' ya da 'A10' olarak ayarlanmalıdır"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "İleti dışa aktarma görevinin GenelAktarıcıAyarları.E-postaAdresi ayarı geçerli bir e-posta adresi olmalıdır"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "İleti dışa aktarma görevi GenelAktarıcıAyarları.SmtpParolası ayarlanmalıdır"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "İleti dışa aktarma görevi GenelAktarıcıAyarları.SmtpKullanıcıAdı ayarlanmalıdır"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "İleti dışa aktarma görevinin GenelAktarıcıE-postaAdresi geçerli bir e-posta adresi olmalıdır"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - 测试邮箱设置"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "请求中图片为空"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v 已移出团队。"
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "请求中图片为空"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "无法解码团队图标"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "无法编码团队图标"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "获取团队时发生错误"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "请求中缺失图片文件"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "无法打开图像文件"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "不能解析混合表单"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "不能上传团队图标。没有配置图片存储。"
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "不能上传团队图标。文件太大。"
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "无法保存团队图标"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "使用电子邮件注册团队被禁用。"
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "无法激活揭开的插件。插件可能已存在并已激活。"
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "保存插件状态到配置出错"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "消息导出任务 ExportFormat 必须为 'actiance' 或 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "消息导出任务 ExportFormat 必须为 'actiance' 或 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "消息导出任务 FileLocation 比如为可写的目录"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "消息导出任务 FileLocation 必须为 FileSettings.Directory 的子目录"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "消息导出任务 GlobalRelayEmailAddress 必须为有效的电子邮箱地址"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "消息导出任务 GlobalRelayEmailAddress 必须为有效的电子邮箱地址"

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

@@ -107,6 +107,18 @@
"id": "api.admin.test_email.subject",
"translation": "Mattermost - 測試電子郵件設定"
},
{
"id": "api.admin.test_s3.missing_s3_bucket",
"translation": "S3 Bucket is required"
},
{
"id": "api.admin.test_s3.missing_s3_endpoint",
"translation": "S3 Endpoint is required"
},
{
"id": "api.admin.test_s3.missing_s3_region",
"translation": "S3 Region is required"
},
{
"id": "api.admin.upload_brand_image.array.app_error",
"translation": "要求的 'image' 欄位為空陣列"
@@ -2330,6 +2342,50 @@
"id": "api.team.remove_user_from_team.removed",
"translation": "%v 已從團隊中移除。"
},
{
"id": "api.team.set_team_icon.array.app_error",
"translation": "要求的 'image' 欄位為空陣列"
},
{
"id": "api.team.set_team_icon.decode.app_error",
"translation": "Could not decode team icon"
},
{
"id": "api.team.set_team_icon.decode_config.app_error",
"translation": "Could not decode team icon metadata"
},
{
"id": "api.team.set_team_icon.encode.app_error",
"translation": "Could not encode team icon"
},
{
"id": "api.team.set_team_icon.get_team.app_error",
"translation": "An error occurred getting the team"
},
{
"id": "api.team.set_team_icon.no_file.app_error",
"translation": "要求的 'image' 欄位沒有檔案"
},
{
"id": "api.team.set_team_icon.open.app_error",
"translation": "無法開啟圖片檔案"
},
{
"id": "api.team.set_team_icon.parse.app_error",
"translation": "無法解析 multipart 表單"
},
{
"id": "api.team.set_team_icon.storage.app_error",
"translation": "無法上傳檔案。尚未設定圖片儲存位置。"
},
{
"id": "api.team.set_team_icon.too_large.app_error",
"translation": "無法上傳圖片檔案。檔案太大。"
},
{
"id": "api.team.set_team_icon.write_file.app_error",
"translation": "Could not save team icon"
},
{
"id": "api.team.signup_team.email_disabled.app_error",
"translation": "使用電子郵件註冊團隊已被停用。"
@@ -3646,6 +3702,10 @@
"id": "app.plugin.activate.app_error",
"translation": "無法啟動已解開的模組。模組可能已存在並已啟動。"
},
{
"id": "app.plugin.cluster.save_config.app_error",
"translation": "The plugin configuration in your config.json file must be updated manually when using ReadOnlyConfig with clustering enabled."
},
{
"id": "app.plugin.config.app_error",
"translation": "儲存模組狀態於設定時錯誤"
@@ -4906,6 +4966,10 @@
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "訊息匯出工作的 ExportFormat 必須為 'actiance' 或 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.export_type.app_error",
"translation": "訊息匯出工作的 ExportFormat 必須為 'actiance' 或 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.file_location.app_error",
"translation": "匯出訊息工作 FileLocation 設定必須為可寫入的目錄,匯出資料將寫入此處"
@@ -4914,6 +4978,26 @@
"id": "model.config.is_valid.message_export.file_location.relative",
"translation": "匯出訊息工作 FileLocation 設定必須為 FileSettings.Directory 的子目錄"
},
{
"id": "model.config.is_valid.message_export.global_relay.config_missing.app_error",
"translation": "Message export job ExportFormat is set to 'globalrelay', but GlobalRelaySettings are missing"
},
{
"id": "model.config.is_valid.message_export.global_relay.customer_type.app_error",
"translation": "Message export GlobalRelaySettings.CustomerType must be set to one of either 'A9' or 'A10'"
},
{
"id": "model.config.is_valid.message_export.global_relay.email_address.app_error",
"translation": "訊息匯出工作的 GlobalRelayEmailAddress 必須為 'actiance' 或 'globalrelay'"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_password.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpPassword must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set"
},
{
"id": "model.config.is_valid.message_export.global_relay_email_address.app_error",
"translation": "訊息匯出工作的 GlobalRelayEmailAddress 必須為 'actiance' 或 'globalrelay'"

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

@@ -318,6 +318,10 @@ func (c *Client4) GetAnalyticsRoute() string {
return fmt.Sprintf("/analytics")
}
func (c *Client4) GetTimezonesRoute() string {
return fmt.Sprintf(c.GetSystemRoute() + "/timezones")
}
func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
}
@@ -3173,6 +3177,18 @@ func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
}
}
// Timezone Section
// GetSupportedTimezone returns a page of supported timezones on the system.
func (c *Client4) GetSupportedTimezone() (SupportedTimezones, *Response) {
if r, err := c.DoApiGet(c.GetTimezonesRoute(), ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return TimezonesFromJson(r.Body), BuildResponse(r)
}
}
// Open Graph Metadata Section
// OpenGraph return the open graph metadata for a particular url if the site have the metadata

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

@@ -1295,6 +1295,9 @@ type SamlSettings struct {
IdpDescriptorUrl *string
AssertionConsumerServiceURL *string
ScopingIDPProviderId *string
ScopingIDPName *string
IdpCertificateFile *string
PublicCertificateFile *string
PrivateKeyFile *string
@@ -1701,6 +1704,16 @@ func (s *MessageExportSettings) SetDefaults() {
}
}
type TimezoneSettings struct {
SupportedTimezonesPath *string
}
func (s *TimezoneSettings) SetDefaults() {
if s.SupportedTimezonesPath == nil {
s.SupportedTimezonesPath = NewString("timezones.json")
}
}
type ConfigFunc func() *Config
type Config struct {
@@ -1734,6 +1747,7 @@ type Config struct {
MessageExportSettings MessageExportSettings
JobSettings JobSettings
PluginSettings PluginSettings
TimezoneSettings TimezoneSettings
}
func (o *Config) Clone() *Config {
@@ -1803,6 +1817,7 @@ func (o *Config) SetDefaults() {
o.JobSettings.SetDefaults()
o.WebrtcSettings.SetDefaults()
o.MessageExportSettings.SetDefaults()
o.TimezoneSettings.SetDefaults()
}
func (o *Config) IsValid() *AppError {

628
model/timezone.go Обычный файл
Просмотреть файл

@@ -0,0 +1,628 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
type SupportedTimezones []string
func TimezonesToJson(timezoneList []string) string {
b, _ := json.Marshal(timezoneList)
return string(b)
}
func TimezonesFromJson(data io.Reader) SupportedTimezones {
var timezones SupportedTimezones
json.NewDecoder(data).Decode(&timezones)
return timezones
}
func DefaultUserTimezone() map[string]string {
defaultTimezone := make(map[string]string)
defaultTimezone["useAutomaticTimezone"] = "true"
defaultTimezone["automaticTimezone"] = ""
defaultTimezone["manualTimezone"] = ""
return defaultTimezone
}
var DefaultSupportedTimezones = []string{
"Africa/Abidjan",
"Africa/Accra",
"Africa/Addis_Ababa",
"Africa/Algiers",
"Africa/Asmara",
"Africa/Asmera",
"Africa/Bamako",
"Africa/Bangui",
"Africa/Banjul",
"Africa/Bissau",
"Africa/Blantyre",
"Africa/Brazzaville",
"Africa/Bujumbura",
"Africa/Cairo",
"Africa/Casablanca",
"Africa/Ceuta",
"Africa/Conakry",
"Africa/Dakar",
"Africa/Dar_es_Salaam",
"Africa/Djibouti",
"Africa/Douala",
"Africa/El_Aaiun",
"Africa/Freetown",
"Africa/Gaborone",
"Africa/Harare",
"Africa/Johannesburg",
"Africa/Juba",
"Africa/Kampala",
"Africa/Khartoum",
"Africa/Kigali",
"Africa/Kinshasa",
"Africa/Lagos",
"Africa/Libreville",
"Africa/Lome",
"Africa/Luanda",
"Africa/Lubumbashi",
"Africa/Lusaka",
"Africa/Malabo",
"Africa/Maputo",
"Africa/Maseru",
"Africa/Mbabane",
"Africa/Mogadishu",
"Africa/Monrovia",
"Africa/Nairobi",
"Africa/Ndjamena",
"Africa/Niamey",
"Africa/Nouakchott",
"Africa/Ouagadougou",
"Africa/Porto-Novo",
"Africa/Sao_Tome",
"Africa/Timbuktu",
"Africa/Tripoli",
"Africa/Tunis",
"Africa/Windhoek",
"America/Adak",
"America/Anchorage",
"America/Anguilla",
"America/Antigua",
"America/Araguaina",
"America/Argentina/Buenos_Aires",
"America/Argentina/Catamarca",
"America/Argentina/ComodRivadavia",
"America/Argentina/Cordoba",
"America/Argentina/Jujuy",
"America/Argentina/La_Rioja",
"America/Argentina/Mendoza",
"America/Argentina/Rio_Gallegos",
"America/Argentina/Salta",
"America/Argentina/San_Juan",
"America/Argentina/San_Luis",
"America/Argentina/Tucuman",
"America/Argentina/Ushuaia",
"America/Aruba",
"America/Asuncion",
"America/Atikokan",
"America/Atka",
"America/Bahia",
"America/Bahia_Banderas",
"America/Barbados",
"America/Belem",
"America/Belize",
"America/Blanc-Sablon",
"America/Boa_Vista",
"America/Bogota",
"America/Boise",
"America/Buenos_Aires",
"America/Cambridge_Bay",
"America/Campo_Grande",
"America/Cancun",
"America/Caracas",
"America/Catamarca",
"America/Cayenne",
"America/Cayman",
"America/Chicago",
"America/Chihuahua",
"America/Coral_Harbour",
"America/Cordoba",
"America/Costa_Rica",
"America/Creston",
"America/Cuiaba",
"America/Curacao",
"America/Danmarkshavn",
"America/Dawson",
"America/Dawson_Creek",
"America/Denver",
"America/Detroit",
"America/Dominica",
"America/Edmonton",
"America/Eirunepe",
"America/El_Salvador",
"America/Ensenada",
"America/Fort_Nelson",
"America/Fort_Wayne",
"America/Fortaleza",
"America/Glace_Bay",
"America/Godthab",
"America/Goose_Bay",
"America/Grand_Turk",
"America/Grenada",
"America/Guadeloupe",
"America/Guatemala",
"America/Guayaquil",
"America/Guyana",
"America/Halifax",
"America/Havana",
"America/Hermosillo",
"America/Indiana/Indianapolis",
"America/Indiana/Knox",
"America/Indiana/Marengo",
"America/Indiana/Petersburg",
"America/Indiana/Tell_City",
"America/Indiana/Vevay",
"America/Indiana/Vincennes",
"America/Indiana/Winamac",
"America/Indianapolis",
"America/Inuvik",
"America/Iqaluit",
"America/Jamaica",
"America/Jujuy",
"America/Juneau",
"America/Kentucky/Louisville",
"America/Kentucky/Monticello",
"America/Knox_IN",
"America/Kralendijk",
"America/La_Paz",
"America/Lima",
"America/Los_Angeles",
"America/Louisville",
"America/Lower_Princes",
"America/Maceio",
"America/Managua",
"America/Manaus",
"America/Marigot",
"America/Martinique",
"America/Matamoros",
"America/Mazatlan",
"America/Mendoza",
"America/Menominee",
"America/Merida",
"America/Metlakatla",
"America/Mexico_City",
"America/Miquelon",
"America/Moncton",
"America/Monterrey",
"America/Montevideo",
"America/Montreal",
"America/Montserrat",
"America/Nassau",
"America/New_York",
"America/Nipigon",
"America/Nome",
"America/Noronha",
"America/North_Dakota/Beulah",
"America/North_Dakota/Center",
"America/North_Dakota/New_Salem",
"America/Ojinaga",
"America/Panama",
"America/Pangnirtung",
"America/Paramaribo",
"America/Phoenix",
"America/Port-au-Prince",
"America/Port_of_Spain",
"America/Porto_Acre",
"America/Porto_Velho",
"America/Puerto_Rico",
"America/Punta_Arenas",
"America/Rainy_River",
"America/Rankin_Inlet",
"America/Recife",
"America/Regina",
"America/Resolute",
"America/Rio_Branco",
"America/Rosario",
"America/Santa_Isabel",
"America/Santarem",
"America/Santiago",
"America/Santo_Domingo",
"America/Sao_Paulo",
"America/Scoresbysund",
"America/Shiprock",
"America/Sitka",
"America/St_Barthelemy",
"America/St_Johns",
"America/St_Kitts",
"America/St_Lucia",
"America/St_Thomas",
"America/St_Vincent",
"America/Swift_Current",
"America/Tegucigalpa",
"America/Thule",
"America/Thunder_Bay",
"America/Tijuana",
"America/Toronto",
"America/Tortola",
"America/Vancouver",
"America/Virgin",
"America/Whitehorse",
"America/Winnipeg",
"America/Yakutat",
"America/Yellowknife",
"Antarctica/Casey",
"Antarctica/Davis",
"Antarctica/DumontDUrville",
"Antarctica/Macquarie",
"Antarctica/Mawson",
"Antarctica/McMurdo",
"Antarctica/Palmer",
"Antarctica/Rothera",
"Antarctica/South_Pole",
"Antarctica/Syowa",
"Antarctica/Troll",
"Antarctica/Vostok",
"Arctic/Longyearbyen",
"Asia/Aden",
"Asia/Almaty",
"Asia/Amman",
"Asia/Anadyr",
"Asia/Aqtau",
"Asia/Aqtobe",
"Asia/Ashgabat",
"Asia/Ashkhabad",
"Asia/Atyrau",
"Asia/Baghdad",
"Asia/Bahrain",
"Asia/Baku",
"Asia/Bangkok",
"Asia/Barnaul",
"Asia/Beirut",
"Asia/Bishkek",
"Asia/Brunei",
"Asia/Calcutta",
"Asia/Chita",
"Asia/Choibalsan",
"Asia/Chongqing",
"Asia/Chungking",
"Asia/Colombo",
"Asia/Dacca",
"Asia/Damascus",
"Asia/Dhaka",
"Asia/Dili",
"Asia/Dubai",
"Asia/Dushanbe",
"Asia/Famagusta",
"Asia/Gaza",
"Asia/Harbin",
"Asia/Hebron",
"Asia/Ho_Chi_Minh",
"Asia/Hong_Kong",
"Asia/Hovd",
"Asia/Irkutsk",
"Asia/Istanbul",
"Asia/Jakarta",
"Asia/Jayapura",
"Asia/Jerusalem",
"Asia/Kabul",
"Asia/Kamchatka",
"Asia/Karachi",
"Asia/Kashgar",
"Asia/Kathmandu",
"Asia/Katmandu",
"Asia/Khandyga",
"Asia/Kolkata",
"Asia/Krasnoyarsk",
"Asia/Kuala_Lumpur",
"Asia/Kuching",
"Asia/Kuwait",
"Asia/Macao",
"Asia/Macau",
"Asia/Magadan",
"Asia/Makassar",
"Asia/Manila",
"Asia/Muscat",
"Asia/Nicosia",
"Asia/Novokuznetsk",
"Asia/Novosibirsk",
"Asia/Omsk",
"Asia/Oral",
"Asia/Phnom_Penh",
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
"Asia/Saigon",
"Asia/Sakhalin",
"Asia/Samarkand",
"Asia/Seoul",
"Asia/Shanghai",
"Asia/Singapore",
"Asia/Srednekolymsk",
"Asia/Taipei",
"Asia/Tashkent",
"Asia/Tbilisi",
"Asia/Tehran",
"Asia/Tel_Aviv",
"Asia/Thimbu",
"Asia/Thimphu",
"Asia/Tokyo",
"Asia/Tomsk",
"Asia/Ujung_Pandang",
"Asia/Ulaanbaatar",
"Asia/Ulan_Bator",
"Asia/Urumqi",
"Asia/Ust-Nera",
"Asia/Vientiane",
"Asia/Vladivostok",
"Asia/Yakutsk",
"Asia/Yangon",
"Asia/Yekaterinburg",
"Asia/Yerevan",
"Atlantic/Azores",
"Atlantic/Bermuda",
"Atlantic/Canary",
"Atlantic/Cape_Verde",
"Atlantic/Faeroe",
"Atlantic/Faroe",
"Atlantic/Jan_Mayen",
"Atlantic/Madeira",
"Atlantic/Reykjavik",
"Atlantic/South_Georgia",
"Atlantic/St_Helena",
"Atlantic/Stanley",
"Australia/ACT",
"Australia/Adelaide",
"Australia/Brisbane",
"Australia/Broken_Hill",
"Australia/Canberra",
"Australia/Currie",
"Australia/Darwin",
"Australia/Eucla",
"Australia/Hobart",
"Australia/LHI",
"Australia/Lindeman",
"Australia/Lord_Howe",
"Australia/Melbourne",
"Australia/NSW",
"Australia/North",
"Australia/Perth",
"Australia/Queensland",
"Australia/South",
"Australia/Sydney",
"Australia/Tasmania",
"Australia/Victoria",
"Australia/West",
"Australia/Yancowinna",
"Brazil/Acre",
"Brazil/DeNoronha",
"Brazil/East",
"Brazil/West",
"CET",
"CST6CDT",
"Canada/Atlantic",
"Canada/Central",
"Canada/East-Saskatchewan",
"Canada/Eastern",
"Canada/Mountain",
"Canada/Newfoundland",
"Canada/Pacific",
"Canada/Saskatchewan",
"Canada/Yukon",
"Chile/Continental",
"Chile/EasterIsland",
"Cuba",
"EET",
"EST",
"EST5EDT",
"Egypt",
"Eire",
"Etc/GMT",
"Etc/GMT+0",
"Etc/GMT+1",
"Etc/GMT+10",
"Etc/GMT+11",
"Etc/GMT+12",
"Etc/GMT+2",
"Etc/GMT+3",
"Etc/GMT+4",
"Etc/GMT+5",
"Etc/GMT+6",
"Etc/GMT+7",
"Etc/GMT+8",
"Etc/GMT+9",
"Etc/GMT-0",
"Etc/GMT-1",
"Etc/GMT-10",
"Etc/GMT-11",
"Etc/GMT-12",
"Etc/GMT-13",
"Etc/GMT-14",
"Etc/GMT-2",
"Etc/GMT-3",
"Etc/GMT-4",
"Etc/GMT-5",
"Etc/GMT-6",
"Etc/GMT-7",
"Etc/GMT-8",
"Etc/GMT-9",
"Etc/GMT0",
"Etc/Greenwich",
"Etc/UCT",
"Etc/UTC",
"Etc/Universal",
"Etc/Zulu",
"Europe/Amsterdam",
"Europe/Andorra",
"Europe/Astrakhan",
"Europe/Athens",
"Europe/Belfast",
"Europe/Belgrade",
"Europe/Berlin",
"Europe/Bratislava",
"Europe/Brussels",
"Europe/Bucharest",
"Europe/Budapest",
"Europe/Busingen",
"Europe/Chisinau",
"Europe/Copenhagen",
"Europe/Dublin",
"Europe/Gibraltar",
"Europe/Guernsey",
"Europe/Helsinki",
"Europe/Isle_of_Man",
"Europe/Istanbul",
"Europe/Jersey",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Kirov",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
"Europe/Luxembourg",
"Europe/Madrid",
"Europe/Malta",
"Europe/Mariehamn",
"Europe/Minsk",
"Europe/Monaco",
"Europe/Moscow",
"Europe/Nicosia",
"Europe/Oslo",
"Europe/Paris",
"Europe/Podgorica",
"Europe/Prague",
"Europe/Riga",
"Europe/Rome",
"Europe/Samara",
"Europe/San_Marino",
"Europe/Sarajevo",
"Europe/Saratov",
"Europe/Simferopol",
"Europe/Skopje",
"Europe/Sofia",
"Europe/Stockholm",
"Europe/Tallinn",
"Europe/Tirane",
"Europe/Tiraspol",
"Europe/Ulyanovsk",
"Europe/Uzhgorod",
"Europe/Vaduz",
"Europe/Vatican",
"Europe/Vienna",
"Europe/Vilnius",
"Europe/Volgograd",
"Europe/Warsaw",
"Europe/Zagreb",
"Europe/Zaporozhye",
"Europe/Zurich",
"Factory",
"GB",
"GB-Eire",
"GMT",
"GMT+0",
"GMT-0",
"GMT0",
"Greenwich",
"HST",
"Hongkong",
"Iceland",
"Indian/Antananarivo",
"Indian/Chagos",
"Indian/Christmas",
"Indian/Cocos",
"Indian/Comoro",
"Indian/Kerguelen",
"Indian/Mahe",
"Indian/Maldives",
"Indian/Mauritius",
"Indian/Mayotte",
"Indian/Reunion",
"Iran",
"Israel",
"Jamaica",
"Japan",
"Kwajalein",
"Libya",
"MET",
"MST",
"MST7MDT",
"Mexico/BajaNorte",
"Mexico/BajaSur",
"Mexico/General",
"NZ",
"NZ-CHAT",
"Navajo",
"PRC",
"PST8PDT",
"Pacific/Apia",
"Pacific/Auckland",
"Pacific/Bougainville",
"Pacific/Chatham",
"Pacific/Chuuk",
"Pacific/Easter",
"Pacific/Efate",
"Pacific/Enderbury",
"Pacific/Fakaofo",
"Pacific/Fiji",
"Pacific/Funafuti",
"Pacific/Galapagos",
"Pacific/Gambier",
"Pacific/Guadalcanal",
"Pacific/Guam",
"Pacific/Honolulu",
"Pacific/Johnston",
"Pacific/Kiritimati",
"Pacific/Kosrae",
"Pacific/Kwajalein",
"Pacific/Majuro",
"Pacific/Marquesas",
"Pacific/Midway",
"Pacific/Nauru",
"Pacific/Niue",
"Pacific/Norfolk",
"Pacific/Noumea",
"Pacific/Pago_Pago",
"Pacific/Palau",
"Pacific/Pitcairn",
"Pacific/Pohnpei",
"Pacific/Ponape",
"Pacific/Port_Moresby",
"Pacific/Rarotonga",
"Pacific/Saipan",
"Pacific/Samoa",
"Pacific/Tahiti",
"Pacific/Tarawa",
"Pacific/Tongatapu",
"Pacific/Truk",
"Pacific/Wake",
"Pacific/Wallis",
"Pacific/Yap",
"Poland",
"Portugal",
"ROC",
"ROK",
"Singapore",
"Turkey",
"UCT",
"US/Alaska",
"US/Aleutian",
"US/Arizona",
"US/Central",
"US/East-Indiana",
"US/Eastern",
"US/Hawaii",
"US/Indiana-Starke",
"US/Michigan",
"US/Mountain",
"US/Pacific",
"US/Pacific-New",
"US/Samoa",
"UTC",
"Universal",
"W-SU",
"WET",
"Zulu",
}

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

@@ -71,6 +71,7 @@ type User struct {
LastPictureUpdate int64 `json:"last_picture_update,omitempty"`
FailedAttempts int `json:"failed_attempts,omitempty"`
Locale string `json:"locale"`
Timezone StringMap `json:"timezone"`
MfaActive bool `json:"mfa_active,omitempty"`
MfaSecret string `json:"mfa_secret,omitempty"`
LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"`
@@ -86,6 +87,7 @@ type UserPatch struct {
Props StringMap `json:"props,omitempty"`
NotifyProps StringMap `json:"notify_props,omitempty"`
Locale *string `json:"locale"`
Timezone StringMap `json:"timezone"`
}
type UserAuth struct {
@@ -208,6 +210,10 @@ func (u *User) PreSave() {
u.SetDefaultNotifications()
}
if u.Timezone == nil {
u.Props = make(map[string]string)
}
if len(u.Password) > 0 {
u.Password = HashPassword(u.Password)
}
@@ -302,6 +308,10 @@ func (u *User) Patch(patch *UserPatch) {
if patch.Locale != nil {
u.Locale = *patch.Locale
}
if patch.Timezone != nil {
u.Timezone = patch.Timezone
}
}
// ToJson convert a User to a json string

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

@@ -4,6 +4,7 @@
package sqlstore
import (
"encoding/json"
"os"
"strings"
"time"
@@ -380,6 +381,12 @@ func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
//TODO: Uncomment the following condition when version 4.9.0 is released
//if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_9_0) {
sqlStore.CreateColumnIfNotExists("Teams", "LastTeamIconUpdate", "bigint", "bigint", "0")
defaultTimezone := model.DefaultUserTimezone()
defaultTimezoneValue, err := json.Marshal(defaultTimezone)
if err != nil {
l4g.Critical(err)
}
sqlStore.CreateColumnIfNotExists("Users", "Timezone", "varchar(256)", "varchar(256)", string(defaultTimezoneValue))
// saveSchemaVersion(sqlStore, VERSION_4_9_0)
//}
}

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

@@ -79,6 +79,7 @@ func NewSqlUserStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) st
table.ColMap("Locale").SetMaxSize(5)
table.ColMap("MfaSecret").SetMaxSize(128)
table.ColMap("Position").SetMaxSize(128)
table.ColMap("Timezone").SetMaxSize(256)
}
return us

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

@@ -9,7 +9,6 @@ import (
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strconv"
"strings"
@@ -51,21 +50,17 @@ func FindConfigFile(fileName string) (path string) {
return ""
}
// FindDir looks for the given directory in nearby ancestors, falling back to `./` if not found.
func FindDir(dir string) (string, bool) {
fileName := "."
found := false
if _, err := os.Stat("./" + dir + "/"); err == nil {
fileName, _ = filepath.Abs("./" + dir + "/")
found = true
} else if _, err := os.Stat("../" + dir + "/"); err == nil {
fileName, _ = filepath.Abs("../" + dir + "/")
found = true
} else if _, err := os.Stat("../../" + dir + "/"); err == nil {
fileName, _ = filepath.Abs("../../" + dir + "/")
found = true
for _, parent := range []string{".", "..", "../.."} {
foundDir, err := filepath.Abs(filepath.Join(parent, dir))
if err != nil {
continue
} else if _, err := os.Stat(foundDir); err == nil {
return foundDir, true
}
}
return fileName + "/", found
return "./", false
}
func DisableDebugLogForTest() {
@@ -136,11 +131,10 @@ func ConfigureLog(s *model.LogSettings) {
func GetLogFileLocation(fileLocation string) string {
if fileLocation == "" {
logDir, _ := FindDir("logs")
return logDir + LOG_FILENAME
} else {
return path.Join(fileLocation, LOG_FILENAME)
fileLocation, _ = FindDir("logs")
}
return filepath.Join(fileLocation, LOG_FILENAME)
}
func SaveConfig(fileName string, config *model.Config) *model.AppError {
@@ -414,8 +408,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["SupportEmail"] = *c.SupportSettings.SupportEmail
props["EnableFileAttachments"] = strconv.FormatBool(*c.FileSettings.EnableFileAttachments)
props["EnableMobileFileUpload"] = strconv.FormatBool(*c.FileSettings.EnableMobileUpload)
props["EnableMobileFileDownload"] = strconv.FormatBool(*c.FileSettings.EnableMobileDownload)
props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink)
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
@@ -449,8 +441,55 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
hasImageProxy := c.ServiceSettings.ImageProxyType != nil && *c.ServiceSettings.ImageProxyType != "" && c.ServiceSettings.ImageProxyURL != nil && *c.ServiceSettings.ImageProxyURL != ""
props["HasImageProxy"] = strconv.FormatBool(hasImageProxy)
// Set default values for all options that require a license.
props["ExperimentalTownSquareIsReadOnly"] = "false"
props["ExperimentalEnableAuthenticationTransfer"] = "true"
props["EnableCustomBrand"] = "false"
props["CustomBrandText"] = ""
props["CustomDescriptionText"] = ""
props["EnableLdap"] = "false"
props["LdapLoginFieldName"] = ""
props["LdapNicknameAttributeSet"] = "false"
props["LdapFirstNameAttributeSet"] = "false"
props["LdapLastNameAttributeSet"] = "false"
props["LdapLoginButtonColor"] = ""
props["LdapLoginButtonBorderColor"] = ""
props["LdapLoginButtonTextColor"] = ""
props["EnableMultifactorAuthentication"] = "false"
props["EnforceMultifactorAuthentication"] = "false"
props["EnableCompliance"] = "false"
props["EnableMobileFileDownload"] = "true"
props["EnableMobileFileUpload"] = "true"
props["EnableSaml"] = "false"
props["SamlLoginButtonText"] = ""
props["SamlFirstNameAttributeSet"] = "false"
props["SamlLastNameAttributeSet"] = "false"
props["SamlNicknameAttributeSet"] = "false"
props["SamlLoginButtonColor"] = ""
props["SamlLoginButtonBorderColor"] = ""
props["SamlLoginButtonTextColor"] = ""
props["EnableCluster"] = "false"
props["EnableMetrics"] = "false"
props["EnableSignUpWithGoogle"] = "false"
props["EnableSignUpWithOffice365"] = "false"
props["PasswordMinimumLength"] = "0"
props["PasswordRequireLowercase"] = "false"
props["PasswordRequireUppercase"] = "false"
props["PasswordRequireNumber"] = "false"
props["PasswordRequireSymbol"] = "false"
props["EnableBanner"] = "false"
props["BannerText"] = ""
props["BannerColor"] = ""
props["BannerTextColor"] = ""
props["AllowBannerDismissal"] = "false"
props["EnableThemeSelection"] = "true"
props["DefaultTheme"] = ""
props["AllowCustomThemes"] = "true"
props["AllowedThemes"] = ""
props["DataRetentionEnableMessageDeletion"] = "false"
props["DataRetentionMessageRetentionDays"] = "0"
props["DataRetentionEnableFileDeletion"] = "false"
props["DataRetentionFileRetentionDays"] = "0"
if license != nil {
props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly)
@@ -480,6 +519,8 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
if *license.Features.Compliance {
props["EnableCompliance"] = strconv.FormatBool(*c.ComplianceSettings.Enable)
props["EnableMobileFileDownload"] = strconv.FormatBool(*c.FileSettings.EnableMobileDownload)
props["EnableMobileFileUpload"] = strconv.FormatBool(*c.FileSettings.EnableMobileUpload)
}
if *license.Features.SAML {

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

@@ -12,6 +12,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/model"
)
func TestConfig(t *testing.T) {
@@ -21,6 +23,15 @@ func TestConfig(t *testing.T) {
InitTranslations(cfg.LocalizationSettings)
}
func TestTimezoneConfig(t *testing.T) {
TranslationsPreInit()
supportedTimezones := LoadTimezones("timezones.json")
assert.Equal(t, len(supportedTimezones) > 0, true)
supportedTimezones2 := LoadTimezones("timezones_file_does_not_exists.json")
assert.Equal(t, len(supportedTimezones2) > 0, true)
}
func TestFindConfigFile(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
@@ -193,14 +204,97 @@ func TestValidateLocales(t *testing.T) {
}
func TestGetClientConfig(t *testing.T) {
TranslationsPreInit()
cfg, _, err := LoadConfig("config.json")
require.Nil(t, err)
configMap := GenerateClientConfig(cfg, "", nil)
if configMap["EmailNotificationContentsType"] != *cfg.EmailSettings.EmailNotificationContentsType {
t.Fatal("EmailSettings.EmailNotificationContentsType not exposed to client config")
t.Parallel()
testCases := []struct {
description string
config *model.Config
diagnosticId string
license *model.License
expectedFields map[string]string
}{
{
"unlicensed",
&model.Config{
EmailSettings: model.EmailSettings{
EmailNotificationContentsType: sToP(model.EMAIL_NOTIFICATION_CONTENTS_FULL),
},
ThemeSettings: model.ThemeSettings{
// Ignored, since not licensed.
AllowCustomThemes: bToP(false),
},
},
"",
nil,
map[string]string{
"DiagnosticId": "",
"EmailNotificationContentsType": "full",
"AllowCustomThemes": "true",
},
},
{
"licensed, but not for theme management",
&model.Config{
EmailSettings: model.EmailSettings{
EmailNotificationContentsType: sToP(model.EMAIL_NOTIFICATION_CONTENTS_FULL),
},
ThemeSettings: model.ThemeSettings{
// Ignored, since not licensed.
AllowCustomThemes: bToP(false),
},
},
"tag1",
&model.License{
Features: &model.Features{
ThemeManagement: bToP(false),
},
},
map[string]string{
"DiagnosticId": "tag1",
"EmailNotificationContentsType": "full",
"AllowCustomThemes": "true",
},
},
{
"licensed for theme management",
&model.Config{
EmailSettings: model.EmailSettings{
EmailNotificationContentsType: sToP(model.EMAIL_NOTIFICATION_CONTENTS_FULL),
},
ThemeSettings: model.ThemeSettings{
AllowCustomThemes: bToP(false),
},
},
"tag2",
&model.License{
Features: &model.Features{
ThemeManagement: bToP(true),
},
},
map[string]string{
"DiagnosticId": "tag2",
"EmailNotificationContentsType": "full",
"AllowCustomThemes": "false",
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.description, func(t *testing.T) {
t.Parallel()
testCase.config.SetDefaults()
if testCase.license != nil {
testCase.license.Features.SetDefaults()
}
configMap := GenerateClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
for expectedField, expectedValue := range testCase.expectedFields {
assert.Equal(t, expectedValue, configMap[expectedField])
}
})
}
}
func TestReadConfig(t *testing.T) {
@@ -213,3 +307,11 @@ func TestReadConfig(t *testing.T) {
assert.Equal(t, "http://foo.bar", *config.ServiceSettings.SiteURL)
}
func sToP(s string) *string {
return &s
}
func bToP(b bool) *bool {
return &b
}

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

@@ -5,8 +5,10 @@ package utils
import (
"bytes"
"errors"
"html/template"
"io"
"path/filepath"
"reflect"
"sync/atomic"
@@ -39,7 +41,7 @@ func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
return nil, err
}
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
if htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html")); err != nil {
return nil, err
} else {
ret.templates.Store(htmlTemplates)
@@ -56,7 +58,7 @@ func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
l4g.Info("Re-parsing templates because of modified file %v", event.Name)
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
if htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html")); err != nil {
l4g.Error("Failed to parse templates %v", err)
} else {
ret.templates.Store(htmlTemplates)
@@ -103,6 +105,10 @@ func (t *HTMLTemplate) Render() string {
}
func (t *HTMLTemplate) RenderToWriter(w io.Writer) error {
if t.Templates == nil {
return errors.New("no html templates")
}
if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil {
l4g.Error(T("api.api.render.error"), t.TemplateName, err)
return err

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

@@ -23,13 +23,15 @@ var settings model.LocalizationSettings
// this functions loads translations from filesystem
// and assign english while loading server config
func TranslationsPreInit() error {
// Set T even if we fail to load the translations. Lots of shutdown handling code will
// segfault trying to handle the error, and the untranslated IDs are strictly better.
T = TfuncWithFallback("en")
TDefault = TfuncWithFallback("en")
if err := InitTranslationsWithDir("i18n"); err != nil {
return err
}
T = TfuncWithFallback("en")
TDefault = TfuncWithFallback("en")
return nil
}
@@ -51,9 +53,9 @@ func InitTranslationsWithDir(dir string) error {
for _, f := range files {
if filepath.Ext(f.Name()) == ".json" {
filename := f.Name()
locales[strings.Split(filename, ".")[0]] = i18nDirectory + filename
locales[strings.Split(filename, ".")[0]] = filepath.Join(i18nDirectory, filename)
if err := i18n.LoadTranslationFile(i18nDirectory + filename); err != nil {
if err := i18n.LoadTranslationFile(filepath.Join(i18nDirectory, filename)); err != nil {
return err
}
}

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

@@ -12,6 +12,7 @@ import (
"encoding/pem"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
@@ -114,7 +115,7 @@ func GetLicenseFileFromDisk(fileName string) []byte {
func GetLicenseFileLocation(fileLocation string) string {
if fileLocation == "" {
configDir, _ := FindDir("config")
return configDir + "mattermost.mattermost-license"
return filepath.Join(configDir, "mattermost.mattermost-license")
} else {
return fileLocation
}

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

@@ -221,10 +221,10 @@ func SendMailUsingConfigAdvanced(mimeTo, smtpTo string, from mail.Address, subje
return err
}
return SendMail(c, mimeTo, smtpTo, from, subject, htmlBody, attachments, mimeHeaders, fileBackend)
return SendMail(c, mimeTo, smtpTo, from, subject, htmlBody, attachments, mimeHeaders, fileBackend, time.Now())
}
func SendMail(c *smtp.Client, mimeTo, smtpTo string, from mail.Address, subject, htmlBody string, attachments []*model.FileInfo, mimeHeaders map[string]string, fileBackend FileBackend) *model.AppError {
func SendMail(c *smtp.Client, mimeTo, smtpTo string, from mail.Address, subject, htmlBody string, attachments []*model.FileInfo, mimeHeaders map[string]string, fileBackend FileBackend, date time.Time) *model.AppError {
l4g.Debug(T("utils.mail.send_mail.sending.debug"), mimeTo, subject)
htmlMessage := "\r\n<html><body>" + htmlBody + "</body></html>"
@@ -249,7 +249,7 @@ func SendMail(c *smtp.Client, mimeTo, smtpTo string, from mail.Address, subject,
m := gomail.NewMessage(gomail.SetCharset("UTF-8"))
m.SetHeaders(headers)
m.SetDateHeader("Date", time.Now())
m.SetDateHeader("Date", date)
m.SetBody("text/plain", txtBody)
m.AddAlternative("text/html", htmlMessage)

25
utils/timezone.go Обычный файл
Просмотреть файл

@@ -0,0 +1,25 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package utils
import (
"encoding/json"
"io/ioutil"
"github.com/mattermost/mattermost-server/model"
)
func LoadTimezones(fileName string) model.SupportedTimezones {
var supportedTimezones model.SupportedTimezones
if timezoneFile := FindConfigFile(fileName); timezoneFile == "" {
return model.DefaultSupportedTimezones
} else if raw, err := ioutil.ReadFile(timezoneFile); err != nil {
return model.DefaultSupportedTimezones
} else if err := json.Unmarshal(raw, &supportedTimezones); err != nil {
return model.DefaultSupportedTimezones
} else {
return supportedTimezones
}
}

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

@@ -5,6 +5,7 @@ package web
import (
"net/http"
"path/filepath"
"strings"
"github.com/NYTimes/gziphandler"
@@ -102,5 +103,5 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
http.ServeFile(w, r, staticDir+"root.html")
http.ServeFile(w, r, filepath.Join(staticDir, "root.html"))
}