1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-18 20:59:43 +02:00

Set org and per user locale

This commit is contained in:
Harvey Kandola 2022-03-19 18:07:38 -04:00
parent 23abcf1585
commit 4494ace0a2
30 changed files with 125 additions and 41 deletions

View file

@ -0,0 +1,5 @@
/* Community Edition */
-- Local aware.
ALTER TABLE dmz_org ADD COLUMN `c_locale` VARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD COLUMN `c_locale` VARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -0,0 +1,5 @@
/* Community Edition */
-- Local aware.
ALTER TABLE dmz_org ADD COLUMN c_locale VARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD COLUMN c_locale VARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -0,0 +1,5 @@
/* Community edition */
-- Local aware.
ALTER TABLE dmz_org ADD c_locale NVARCHAR(20) NOT NULL DEFAULT 'en-US';
ALTER TABLE dmz_user ADD c_locale NVARCHAR(20) NOT NULL DEFAULT 'en-US';

View file

@ -25,6 +25,7 @@ var localeMap map[string]map[string]string
// SupportedLocales returns array of locales. // SupportedLocales returns array of locales.
func SupportedLocales() (locales []string) { func SupportedLocales() (locales []string) {
locales = append(locales, "en-US") locales = append(locales, "en-US")
locales = append(locales, "de-DE")
return return
} }

View file

@ -48,6 +48,7 @@ func AddExternalUser(ctx domain.RequestContext, rt *env.Runtime, store *store.St
if addUser { if addUser {
userID = uniqueid.Generate() userID = uniqueid.Generate()
u.RefID = userID u.RefID = userID
u.Locale = ctx.OrgLocale
err = store.User.Add(ctx, u) err = store.User.Add(ctx, u)
if err != nil { if err != nil {

View file

@ -244,7 +244,7 @@ func (b backerHandler) dmzOrg(files *[]backupItem) (err error) {
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider, c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
coalesce(c_sub,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS subscription, coalesce(c_sub,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS subscription,
coalesce(c_authconfig,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS authconfig, c_maxtags AS maxtags, coalesce(c_authconfig,`+b.Runtime.StoreProvider.JSONEmpty()+`) AS authconfig, c_maxtags AS maxtags,
c_theme AS theme, c_logo AS logo, c_created AS created, c_revised AS revised c_theme AS theme, c_logo AS logo, c_locale as locale, c_created AS created, c_revised AS revised
FROM dmz_org`+w) FROM dmz_org`+w)
if err != nil { if err != nil {
return return
@ -308,7 +308,7 @@ func (b backerHandler) dmzUserAccount(files *[]backupItem) (err error) {
err = b.Runtime.Db.Select(&u, `SELECT u.id, u.c_refid AS refid, err = b.Runtime.Db.Select(&u, `SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised u.c_created AS created, u.c_revised AS revised
FROM dmz_user u`+w) FROM dmz_user u`+w)
if err != nil { if err != nil {

View file

@ -370,14 +370,14 @@ func (r *restoreHandler) dmzOrg() (err error) {
INSERT INTO dmz_org (c_refid, c_company, c_title, c_message, INSERT INTO dmz_org (c_refid, c_company, c_title, c_message,
c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig, c_domain, c_service, c_email, c_anonaccess, c_authprovider, c_authconfig,
c_maxtags, c_verified, c_serial, c_sub, c_active, c_maxtags, c_verified, c_serial, c_sub, c_active,
c_theme, c_logo, c_created, c_revised) c_theme, c_logo, c_locale, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`), VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
org[i].RefID, org[i].Company, org[i].Title, org[i].Message, org[i].RefID, org[i].Company, org[i].Title, org[i].Message,
strings.ToLower(org[i].Domain), org[i].ConversionEndpoint, strings.ToLower(org[i].Email), strings.ToLower(org[i].Domain), org[i].ConversionEndpoint, strings.ToLower(org[i].Email),
org[i].AllowAnonymousAccess, org[i].AuthProvider, org[i].AuthConfig, org[i].AllowAnonymousAccess, org[i].AuthProvider, org[i].AuthConfig,
org[i].MaxTags, r.Runtime.StoreProvider.IsTrue(), org[i].Serial, org[i].MaxTags, r.Runtime.StoreProvider.IsTrue(), org[i].Serial,
org[i].Subscription, org[i].Active, org[i].Subscription, org[i].Active,
org[i].Theme, org[i].Logo, org[i].Theme, org[i].Logo, org[i].Locale,
org[i].Created, org[i].Revised) org[i].Created, org[i].Revised)
if err != nil { if err != nil {
r.Context.Transaction.Rollback() r.Context.Transaction.Rollback()
@ -412,6 +412,7 @@ func (r *restoreHandler) dmzOrg() (err error) {
org[0].Title = r.Spec.Org.Title org[0].Title = r.Spec.Org.Title
org[0].Subscription = r.Spec.Org.Subscription org[0].Subscription = r.Spec.Org.Subscription
org[0].Theme = r.Spec.Org.Theme org[0].Theme = r.Spec.Org.Theme
org[0].Locale = r.Spec.Org.Locale
} }
_, err = r.Context.Transaction.NamedExec(`UPDATE dmz_org SET _, err = r.Context.Transaction.NamedExec(`UPDATE dmz_org SET
@ -425,7 +426,8 @@ func (r *restoreHandler) dmzOrg() (err error) {
c_message=:message, c_message=:message,
c_title=:title, c_title=:title,
c_serial=:serial, c_serial=:serial,
c_sub=:subscription c_sub=:subscription,
c_locale=:locale,
WHERE c_refid=:refid`, &org[0]) WHERE c_refid=:refid`, &org[0])
if err != nil { if err != nil {
r.Context.Transaction.Rollback() r.Context.Transaction.Rollback()
@ -1735,11 +1737,11 @@ func (r *restoreHandler) dmzUser() (err error) {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(` _, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_user INSERT INTO dmz_user
(c_refid, c_firstname, c_lastname, c_email, c_initials, c_globaladmin, (c_refid, c_firstname, c_lastname, c_email, c_initials, c_globaladmin,
c_password, c_salt, c_reset, c_active, c_lastversion, c_created, c_revised) c_password, c_salt, c_reset, c_active, c_lastversion, c_locale, c_created, c_revised)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`), VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
r.remapUser(u[i].RefID), u[i].Firstname, u[i].Lastname, strings.ToLower(u[i].Email), u[i].Initials, r.remapUser(u[i].RefID), u[i].Firstname, u[i].Lastname, strings.ToLower(u[i].Email), u[i].Initials,
u[i].GlobalAdmin, u[i].Password, u[i].Salt, u[i].Reset, u[i].Active, u[i].GlobalAdmin, u[i].Password, u[i].Salt, u[i].Reset, u[i].Active,
u[i].LastVersion, u[i].Created, u[i].Revised) u[i].LastVersion, u[i].Locale, u[i].Created, u[i].Revised)
if err != nil { if err != nil {
r.Context.Transaction.Rollback() r.Context.Transaction.Rollback()

View file

@ -45,6 +45,7 @@ type RequestContext struct {
ViewUsers bool ViewUsers bool
Subscription Subscription Subscription Subscription
Locale string Locale string
OrgLocale string
} }
//GetAppURL returns full HTTP url for the app //GetAppURL returns full HTTP url for the app

View file

@ -69,6 +69,7 @@ func (h *Handler) Meta(w http.ResponseWriter, r *http.Request) {
data.Storage = h.Runtime.StoreProvider.Type() data.Storage = h.Runtime.StoreProvider.Type()
data.Location = h.Runtime.Flags.Location // reserved data.Location = h.Runtime.Flags.Location // reserved
data.Locale = org.Locale data.Locale = org.Locale
data.Locales = i18n.SupportedLocales()
if len(data.Locale) == 0 { if len(data.Locale) == 0 {
data.Locale = i18n.DefaultLocale data.Locale = i18n.DefaultLocale
} }

View file

@ -52,7 +52,7 @@ func (s Store) GetOrganization(ctx domain.RequestContext, id string) (org org.Or
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider, c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig, coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription, coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
c_maxtags AS maxtags, c_theme AS theme, c_created AS created, c_revised AS revised c_maxtags AS maxtags, c_theme AS theme, c_locale as locale, c_created AS created, c_revised AS revised
FROM dmz_org FROM dmz_org
WHERE c_refid=?`), WHERE c_refid=?`),
id) id)
@ -84,7 +84,7 @@ func (s Store) GetOrganizationByDomain(subdomain string) (o org.Organization, er
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider, c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig, coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription, coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
c_maxtags AS maxtags, c_created AS created, c_revised AS revised, c_theme AS theme c_maxtags AS maxtags, c_theme AS theme, c_locale as locale, c_created AS created, c_revised AS revised, c_theme AS theme
FROM dmz_org FROM dmz_org
WHERE c_domain=? AND c_active=`+s.IsTrue()), WHERE c_domain=? AND c_active=`+s.IsTrue()),
subdomain) subdomain)
@ -99,7 +99,7 @@ func (s Store) GetOrganizationByDomain(subdomain string) (o org.Organization, er
c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider, c_anonaccess AS allowanonymousaccess, c_authprovider AS authprovider,
coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig, coalesce(c_authconfig,`+s.EmptyJSON()+`) AS authconfig,
coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription, coalesce(c_sub,`+s.EmptyJSON()+`) AS subscription,
c_maxtags AS maxtags, c_created AS created, c_revised AS revised, c_theme AS theme c_maxtags AS maxtags, c_theme AS theme, c_locale as locale, c_created AS created, c_revised AS revised, c_theme AS theme
FROM dmz_org FROM dmz_org
WHERE c_domain='' AND c_active=`+s.IsTrue())) WHERE c_domain='' AND c_active=`+s.IsTrue()))
@ -116,7 +116,7 @@ func (s Store) UpdateOrganization(ctx domain.RequestContext, org org.Organizatio
_, err = ctx.Transaction.NamedExec(`UPDATE dmz_org SET _, err = ctx.Transaction.NamedExec(`UPDATE dmz_org SET
c_title=:title, c_message=:message, c_service=:conversionendpoint, c_email=:email, c_domain=:domain, c_title=:title, c_message=:message, c_service=:conversionendpoint, c_email=:email, c_domain=:domain,
c_anonaccess=:allowanonymousaccess, c_maxtags=:maxtags, c_theme=:theme, c_revised=:revised c_anonaccess=:allowanonymousaccess, c_maxtags=:maxtags, c_theme=:theme, c_locale=:locale, c_revised=:revised
WHERE c_refid=:refid`, WHERE c_refid=:refid`,
&org) &org)

View file

@ -42,6 +42,7 @@ func inviteNewUserToSharedSpace(ctx domain.RequestContext, rt *env.Runtime, s *s
u.Password = secrets.GeneratePassword(requestedPassword, u.Salt) u.Password = secrets.GeneratePassword(requestedPassword, u.Salt)
userID := uniqueid.Generate() userID := uniqueid.Generate()
u.RefID = userID u.RefID = userID
u.Locale = ctx.OrgLocale
err = s.User.Add(ctx, u) err = s.User.Add(ctx, u)
if err != nil { if err != nil {

View file

@ -136,6 +136,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
if addUser { if addUser {
userID = uniqueid.Generate() userID = uniqueid.Generate()
userModel.RefID = userID userModel.RefID = userID
userModel.Locale = ctx.OrgLocale
err = h.Store.User.Add(ctx, userModel) err = h.Store.User.Add(ctx, userModel)
if err != nil { if err != nil {
@ -781,6 +782,7 @@ func (h *Handler) BulkImport(w http.ResponseWriter, r *http.Request) {
userModel.Firstname = strings.TrimSpace(v[0]) userModel.Firstname = strings.TrimSpace(v[0])
userModel.Lastname = strings.TrimSpace(v[1]) userModel.Lastname = strings.TrimSpace(v[1])
userModel.Email = strings.ToLower(strings.TrimSpace(v[2])) userModel.Email = strings.ToLower(strings.TrimSpace(v[2]))
userModel.Locale = ctx.OrgLocale
if len(userModel.Email) == 0 || len(userModel.Firstname) == 0 || len(userModel.Lastname) == 0 { if len(userModel.Email) == 0 || len(userModel.Firstname) == 0 || len(userModel.Lastname) == 0 {
h.Runtime.Log.Info(method + " missing firstname, lastname, or email") h.Runtime.Log.Info(method + " missing firstname, lastname, or email")

View file

@ -38,8 +38,8 @@ func (s Store) Add(ctx domain.RequestContext, u user.User) (err error) {
u.Created = time.Now().UTC() u.Created = time.Now().UTC()
u.Revised = time.Now().UTC() u.Revised = time.Now().UTC()
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_user (c_refid, c_firstname, c_lastname, c_email, c_initials, c_password, c_salt, c_reset, c_lastversion, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), _, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_user (c_refid, c_firstname, c_lastname, c_email, c_initials, c_password, c_salt, c_reset, c_lastversion, c_locale, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
u.RefID, u.Firstname, u.Lastname, strings.TrimSpace(strings.ToLower(u.Email)), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Created, u.Revised) u.RefID, u.Firstname, u.Lastname, strings.TrimSpace(strings.ToLower(u.Email)), u.Initials, u.Password, u.Salt, "", u.LastVersion, u.Locale, u.Created, u.Revised)
if err != nil { if err != nil {
err = errors.Wrap(err, "execute user insert") err = errors.Wrap(err, "execute user insert")
@ -53,7 +53,7 @@ func (s Store) Get(ctx domain.RequestContext, id string) (u user.User, err error
err = s.Runtime.Db.Get(&u, s.Bind(` err = s.Runtime.Db.Get(&u, s.Bind(`
SELECT id, c_refid AS refid, c_firstname AS firstname, c_lastname AS lastname, c_email AS email, SELECT id, c_refid AS refid, c_firstname AS firstname, c_lastname AS lastname, c_email AS email,
c_initials AS initials, c_globaladmin AS globaladmin, c_password AS password, c_salt AS salt, c_reset AS reset, c_initials AS initials, c_globaladmin AS globaladmin, c_password AS password, c_salt AS salt, c_reset AS reset,
c_lastversion AS lastversion, c_created AS created, c_revised AS revised c_lastversion AS lastversion, c_locale as locale, c_created AS created, c_revised AS revised
FROM dmz_user FROM dmz_user
WHERE c_refid=?`), WHERE c_refid=?`),
id) id)
@ -72,7 +72,7 @@ func (s Store) GetByDomain(ctx domain.RequestContext, domain, email string) (u u
err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised u.c_created AS created, u.c_revised AS revised
FROM dmz_user u, dmz_user_account a, dmz_org o FROM dmz_user u, dmz_user_account a, dmz_org o
WHERE LOWER(u.c_email)=? AND u.c_refid=a.c_userid AND a.c_orgid=o.c_refid AND LOWER(o.c_domain)=?`), WHERE LOWER(u.c_email)=? AND u.c_refid=a.c_userid AND a.c_orgid=o.c_refid AND LOWER(o.c_domain)=?`),
@ -92,7 +92,7 @@ func (s Store) GetByEmail(ctx domain.RequestContext, email string) (u user.User,
err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised u.c_created AS created, u.c_revised AS revised
FROM dmz_user u FROM dmz_user u
WHERE LOWER(u.c_email)=?`), WHERE LOWER(u.c_email)=?`),
@ -110,7 +110,7 @@ func (s Store) GetByToken(ctx domain.RequestContext, token string) (u user.User,
err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised u.c_created AS created, u.c_revised AS revised
FROM dmz_user u FROM dmz_user u
WHERE u.c_reset=?`), WHERE u.c_reset=?`),
@ -130,7 +130,7 @@ func (s Store) GetBySerial(ctx domain.RequestContext, serial string) (u user.Use
err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Get(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised u.c_created AS created, u.c_revised AS revised
FROM dmz_user u FROM dmz_user u
WHERE u.c_salt=?`), WHERE u.c_salt=?`),
@ -151,7 +151,7 @@ func (s Store) GetActiveUsersForOrganization(ctx domain.RequestContext) (u []use
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -176,7 +176,7 @@ func (s Store) GetSpaceUsers(ctx domain.RequestContext, spaceID string) (u []use
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -210,7 +210,7 @@ func (s Store) GetUsersForSpaces(ctx domain.RequestContext, spaces []string) (u
SELECT u.id, u.c_refid AS refid, SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -244,7 +244,7 @@ func (s Store) UpdateUser(ctx domain.RequestContext, u user.User) (err error) {
u.Revised = time.Now().UTC() u.Revised = time.Now().UTC()
u.Email = strings.ToLower(u.Email) u.Email = strings.ToLower(u.Email)
_, err = ctx.Transaction.NamedExec("UPDATE dmz_user SET c_firstname=:firstname, c_lastname=:lastname, c_email=:email, c_revised=:revised, c_initials=:initials, c_lastversion=:lastversion WHERE c_refid=:refid", &u) _, err = ctx.Transaction.NamedExec("UPDATE dmz_user SET c_firstname=:firstname, c_lastname=:lastname, c_email=:email, c_revised=:revised, c_initials=:initials, c_lastversion=:lastversion, c_locale=:locale WHERE c_refid=:refid", &u)
if err != nil { if err != nil {
err = errors.Wrap(err, fmt.Sprintf("execute user update %s", u.RefID)) err = errors.Wrap(err, fmt.Sprintf("execute user update %s", u.RefID))
} }
@ -313,7 +313,7 @@ func (s Store) GetUsersForOrganization(ctx domain.RequestContext, filter string,
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT TOP(`+strconv.Itoa(limit)+`) u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT TOP(`+strconv.Itoa(limit)+`) u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -323,7 +323,7 @@ func (s Store) GetUsersForOrganization(ctx domain.RequestContext, filter string,
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -357,7 +357,7 @@ func (s Store) MatchUsers(ctx domain.RequestContext, text string, maxMatches int
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT TOP(`+strconv.Itoa(maxMatches)+`) u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT TOP(`+strconv.Itoa(maxMatches)+`) u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a
@ -367,7 +367,7 @@ func (s Store) MatchUsers(ctx domain.RequestContext, text string, maxMatches int
err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid, err = s.Runtime.Db.Select(&u, s.Bind(`SELECT u.id, u.c_refid AS refid,
u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email, u.c_firstname AS firstname, u.c_lastname AS lastname, u.c_email AS email,
u.c_initials AS initials, u.c_globaladmin AS globaladmin, u.c_initials AS initials, u.c_globaladmin AS globaladmin,
u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_password AS password, u.c_salt AS salt, u.c_reset AS reset, u.c_lastversion AS lastversion, u.c_locale as locale,
u.c_created AS created, u.c_revised AS revised, u.c_created AS created, u.c_revised AS revised,
a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics a.c_active AS active, a.c_editor AS editor, a.c_admin AS admin, a.c_users AS viewusers, a.c_analytics AS analytics
FROM dmz_user u, dmz_user_account a FROM dmz_user u, dmz_user_account a

View file

@ -39,10 +39,10 @@ func main() {
// Specify the product edition. // Specify the product edition.
rt.Product = domain.Product{} rt.Product = domain.Product{}
rt.Product.Major = "4" rt.Product.Major = "5"
rt.Product.Minor = "2" rt.Product.Minor = "0"
rt.Product.Patch = "3" rt.Product.Patch = "0"
rt.Product.Revision = "220301191336" rt.Product.Revision = "220318131033"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch) rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = domain.CommunityEdition rt.Product.Edition = domain.CommunityEdition
rt.Product.Title = "Community" rt.Product.Title = "Community"

View file

@ -30,12 +30,28 @@ export default Component.extend(Notifier, {
hasTitleInputError: and('titleEmpty', 'titleError'), hasTitleInputError: and('titleEmpty', 'titleError'),
hasMessageInputError: and('messageEmpty', 'messageError'), hasMessageInputError: and('messageEmpty', 'messageError'),
hasConversionEndpointInputError: and('conversionEndpointEmpty', 'conversionEndpointError'), hasConversionEndpointInputError: and('conversionEndpointEmpty', 'conversionEndpointError'),
locale: {},
locales: null,
init() {
this._super(...arguments);
let l = this.get('appMeta.locales');
let t = [];
l.forEach((locale) => {
t.pushObject( {name: locale} );
});
this.set('locales', t);
},
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); this._super(...arguments);
this.set('maxTags', this.get('model.general.maxTags')); this.set('maxTags', this.get('model.general.maxTags'));
this.set('domain', this.get('model.general.domain')); this.set('domain', this.get('model.general.domain'));
this.set('locale', { name: this.get('model.general.locale') });
}, },
didInsertElement() { didInsertElement() {
@ -149,6 +165,10 @@ export default Component.extend(Notifier, {
}, },
actions: { actions: {
onSelectLocale(locale) {
this.set('model.general.locale', locale.name);
},
change() { change() {
const selectEl = $('#maxTags')[0]; const selectEl = $('#maxTags')[0];
const selection = selectEl.selectedOptions[0].value; const selection = selectEl.selectedOptions[0].value;

View file

@ -46,13 +46,34 @@ export default Component.extend(AuthProvider, {
return ''; return '';
} }
}), }),
locale: {},
locales: null,
init() { init() {
this._super(...arguments); this._super(...arguments);
this.password = { password: "", confirmation: "" }; this.password = { password: "", confirmation: "" };
let l = this.get('appMeta.locales');
let t = [];
l.forEach((locale) => {
t.pushObject( {name: locale} );
});
this.set('locales', t);
},
didReceiveAttrs() {
this._super(...arguments);
this.set('locale', { name: this.get('model.locale') });
}, },
actions: { actions: {
onSelectLocale(locale) {
this.set('model.locale', locale.name);
},
save() { save() {
let password = this.get('password.password'); let password = this.get('password.password');
let confirmation = this.get('password.confirmation'); let confirmation = this.get('password.confirmation');

View file

@ -21,6 +21,7 @@ export default Model.extend({
allowAnonymousAccess: attr('boolean', { defaultValue: false }), allowAnonymousAccess: attr('boolean', { defaultValue: false }),
maxTags: attr('number', {defaultValue: 3}), maxTags: attr('number', {defaultValue: 3}),
theme: attr('string'), theme: attr('string'),
locale: attr('string', { defaultValue: "en-US" }),
created: attr(), created: attr(),
revised: attr() revised: attr()
}); });

View file

@ -17,8 +17,7 @@ export default Controller.extend({
actions: { actions: {
onUpdate() { onUpdate() {
return this.get('orgService').save(this.model.general).then(() => { return this.get('orgService').save(this.model.general).then(() => {});
});
}, },
onDefaultLogo(orgId) { onDefaultLogo(orgId) {

View file

@ -31,7 +31,7 @@ export default Route.extend({
dbname: document.head.querySelector("[property=dbname]").content, dbname: document.head.querySelector("[property=dbname]").content,
dbhash: pwd, dbhash: pwd,
title: "", title: "",
message: this.i18n.localize('setup_default_message'), message: "Documize Community instance contains all our documentation",
allowAnonymousAccess: false, allowAnonymousAccess: false,
firstname: "", firstname: "",
lastname: "", lastname: "",

View file

@ -45,6 +45,7 @@ export default Service.extend({
// empty theme uses default theme // empty theme uses default theme
theme: '', theme: '',
locale: '', locale: '',
locales: null,
getBaseUrl(endpoint) { getBaseUrl(endpoint) {
return [this.get('endpoint'), endpoint].join('/'); return [this.get('endpoint'), endpoint].join('/');

View file

@ -35,7 +35,8 @@ export default Service.extend({
message: org.get('message'), message: org.get('message'),
title: org.get('title'), title: org.get('title'),
maxTags: org.get('maxTags'), maxTags: org.get('maxTags'),
conversionEndpoint: org.get('conversionEndpoint') conversionEndpoint: org.get('conversionEndpoint'),
locale: org.get('locale')
}); });
return this.get('ajax').request(`organization/${id}`, { return this.get('ajax').request(`organization/${id}`, {

View file

@ -58,6 +58,10 @@
</select> </select>
<small class="form-text text-muted">{{localize 'customize_tags_explain'}}</small> <small class="form-text text-muted">{{localize 'customize_tags_explain'}}</small>
</div> </div>
<div class="form-group">
<label>{{localize 'locale'}}</label>
{{ui/ui-select content=locales selection=locale optionValuePath="name" optionLabelPath="name" action=(action "onSelectLocale")}}
</div>
{{ui/ui-button color=constants.Color.Green light=true icon=constants.Icon.Settings label=(localize 'save') onClick=(action "save")}} {{ui/ui-button color=constants.Color.Green light=true icon=constants.Icon.Settings label=(localize 'save') onClick=(action "save")}}
</div> </div>

View file

@ -97,7 +97,7 @@
<div id="document-print-modal" class="modal" tabindex="-1" role="dialog"> <div id="document-print-modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header">{{localize 'Print'}}</div> <div class="modal-header">{{localize 'print'}}</div>
<div class="modal-body"> <div class="modal-body">
<p>{{localize 'print_explain'}}</p> <p>{{localize 'print_explain'}}</p>
{{#each pages as |item|}} {{#each pages as |item|}}

View file

@ -1,6 +1,6 @@
{{layout/logo-heading {{layout/logo-heading
title=(localize 'content') title=(localize 'content')
desc=(localize 'setings') desc=(localize 'settings')
icon=constants.Icon.Settings}} icon=constants.Icon.Settings}}
<form class="view-document"> <form class="view-document">

View file

@ -6,7 +6,7 @@
<small class="form-text text-muted">{{localize 'password_strong'}}</small> <small class="form-text text-muted">{{localize 'password_strong'}}</small>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{localize 'confirm_password'}}</label> <label>{{localize 'password_confirm'}}</label>
{{input type="password" value=passwordConfirm id="passwordConfirm" autocomplete="new-password" class=(if hasConfirmError "form-control is-invalid" "form-control")}} {{input type="password" value=passwordConfirm id="passwordConfirm" autocomplete="new-password" class=(if hasConfirmError "form-control is-invalid" "form-control")}}
</div> </div>
<div class="margin-top-10 margin-bottom-20"> <div class="margin-top-10 margin-bottom-20">

View file

@ -11,13 +11,18 @@
<label for="email">{{localize 'email'}}</label> <label for="email">{{localize 'email'}}</label>
{{input id="email" type="email" value=model.email class=(if hasEmailError "form-control is-invalid" "form-control")}} {{input id="email" type="email" value=model.email class=(if hasEmailError "form-control is-invalid" "form-control")}}
</div> </div>
<div class="form-group">
<label>{{localize 'locale'}}</label>
{{ui/ui-select content=locales selection=locale optionValuePath="name" optionLabelPath="name" action=(action "onSelectLocale")}}
</div>
{{#if isAuthProviderDocumize}} {{#if isAuthProviderDocumize}}
<div class="form-group"> <div class="form-group">
<label for="password">{{localize 'password'}}</label> <label for="password">{{localize 'password'}}</label>
{{input id="password" type="password" value=password.password class=(if hasPasswordError "form-control is-invalid" "form-control")}} {{input id="password" type="password" value=password.password class=(if hasPasswordError "form-control is-invalid" "form-control")}}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="confirmPassword">{{localize 'confirm_password'}}</label> <label for="confirmPassword">{{localize 'password_confirm'}}</label>
{{input id="confirmPassword" type="password" value=password.confirmation class=(if hasConfirmPasswordError "form-control is-invalid" "form-control")}} {{input id="confirmPassword" type="password" value=password.confirmation class=(if hasConfirmPasswordError "form-control is-invalid" "form-control")}}
</div> </div>
{{/if}} {{/if}}

View file

@ -124,6 +124,7 @@
"no_access": "Access Denied", "no_access": "Access Denied",
"drag_drop_reorder": "Drag-drop to reorder", "drag_drop_reorder": "Drag-drop to reorder",
"select": "Select", "select": "Select",
"locale": "Locale",
"public": "Public", "public": "Public",
"public_explain": "Public - can be seen by everyone", "public_explain": "Public - can be seen by everyone",
@ -186,6 +187,7 @@
"created": "Created", "created": "Created",
"markdown": "Markdown accepted", "markdown": "Markdown accepted",
"rename": "Rename", "rename": "Rename",
"status": "Status",
"toc": "table of contents", "toc": "table of contents",
"new_canvas": "Blank anvas", "new_canvas": "Blank anvas",

View file

@ -93,4 +93,5 @@ type User struct {
Salt string `json:"salt"` Salt string `json:"salt"`
Reset string `json:"reset"` Reset string `json:"reset"`
LastVersion string `json:"lastVersion"` LastVersion string `json:"lastVersion"`
Locale string `json:"locale"`
} }

View file

@ -46,4 +46,5 @@ type SiteMeta struct {
Theme string `json:"theme"` // default side-wide theme, user overrideble Theme string `json:"theme"` // default side-wide theme, user overrideble
Configured bool `json:"configured"` // is Documize instance configured Configured bool `json:"configured"` // is Documize instance configured
Locale string `json:"locale"` // server default locale Locale string `json:"locale"` // server default locale
Locales []string `json:"locales"` // available locale
} }

View file

@ -131,6 +131,10 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
rc.AppURL = r.Host rc.AppURL = r.Host
rc.Subdomain = organization.GetSubdomainFromHost(r) rc.Subdomain = organization.GetSubdomainFromHost(r)
rc.SSL = request.IsSSL(r) rc.SSL = request.IsSSL(r)
rc.OrgLocale = org.Locale
if len(rc.OrgLocale) == 0 {
rc.OrgLocale = i18n.DefaultLocale
}
// get user IP from request // get user IP from request
i := strings.LastIndex(r.RemoteAddr, ":") i := strings.LastIndex(r.RemoteAddr, ":")
@ -199,7 +203,7 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
rc.Fullname = u.Fullname() rc.Fullname = u.Fullname()
rc.Locale = u.Locale rc.Locale = u.Locale
if len(rc.Locale) == 0 { if len(rc.Locale) == 0 {
u.Locale = i18n.DefaultLocale rc.Locale = i18n.DefaultLocale
} }
// We send back with every HTTP request/response cycle the latest // We send back with every HTTP request/response cycle the latest